Full Code of fossasia/knittingpattern for AI

master e44042988418 cached
162 files
360.5 KB
96.4k tokens
925 symbols
2 requests
Download .txt
Showing preview only (398K chars total). Download the full file or copy to clipboard to get everything.
Repository: fossasia/knittingpattern
Branch: master
Commit: e44042988418
Files: 162
Total size: 360.5 KB

Directory structure:
gitextract_h52otm60/

├── .codeclimate.yml
├── .gitignore
├── .landscape.yaml
├── .travis.yml
├── CONTRIBUTING.rst
├── DeveloperCertificateOfOrigin.txt
├── LICENSE
├── MANIFEST.in
├── README.rst
├── appveyor.yml
├── dev-requirements.in
├── dev-requirements.txt
├── docs/
│   ├── DevelopmentSetup.rst
│   ├── FileFormatSpecification.rst
│   ├── Installation.rst
│   ├── Makefile
│   ├── _static/
│   │   └── .gitignore
│   ├── _templates/
│   │   └── .gitignore
│   ├── conf.py
│   ├── index.rst
│   ├── make.bat
│   ├── make_html.bat
│   ├── reference/
│   │   ├── index.rst
│   │   └── knittingpattern/
│   │       ├── Dumper/
│   │       │   ├── FileWrapper.rst
│   │       │   ├── file.rst
│   │       │   ├── index.rst
│   │       │   ├── init.rst
│   │       │   ├── json.rst
│   │       │   ├── svg.rst
│   │       │   └── xml.rst
│   │       ├── IdCollection.rst
│   │       ├── Instruction.rst
│   │       ├── InstructionLibrary.rst
│   │       ├── KnittingPattern.rst
│   │       ├── KnittingPatternSet.rst
│   │       ├── Loader.rst
│   │       ├── Mesh.rst
│   │       ├── Parser.rst
│   │       ├── ParsingSpecification.rst
│   │       ├── Prototype.rst
│   │       ├── Row.rst
│   │       ├── convert/
│   │       │   ├── AYABPNGBuilder.rst
│   │       │   ├── AYABPNGDumper.rst
│   │       │   ├── InstructionSVGCache.rst
│   │       │   ├── InstructionToSVG.rst
│   │       │   ├── KnittingPatternToSVG.rst
│   │       │   ├── Layout.rst
│   │       │   ├── SVGBuilder.rst
│   │       │   ├── color.rst
│   │       │   ├── image_to_knittingpattern.rst
│   │       │   ├── index.rst
│   │       │   ├── init.rst
│   │       │   └── load_and_dump.rst
│   │       ├── index.rst
│   │       ├── init.rst
│   │       ├── utils.rst
│   │       └── walk.rst
│   └── test/
│       ├── test_docs.py
│       ├── test_documentation_sources_exist.py
│       └── test_sphinx_build.py
├── knittingpattern/
│   ├── Dumper/
│   │   ├── FileWrapper.py
│   │   ├── __init__.py
│   │   ├── file.py
│   │   ├── json.py
│   │   ├── svg.py
│   │   └── xml.py
│   ├── IdCollection.py
│   ├── Instruction.py
│   ├── InstructionLibrary.py
│   ├── KnittingPattern.py
│   ├── KnittingPatternSet.py
│   ├── Loader.py
│   ├── Mesh.py
│   ├── Parser.py
│   ├── ParsingSpecification.py
│   ├── Prototype.py
│   ├── Row.py
│   ├── __init__.py
│   ├── convert/
│   │   ├── AYABPNGBuilder.py
│   │   ├── AYABPNGDumper.py
│   │   ├── InstructionSVGCache.py
│   │   ├── InstructionToSVG.py
│   │   ├── KnittingPatternToSVG.py
│   │   ├── Layout.py
│   │   ├── SVGBuilder.py
│   │   ├── __init__.py
│   │   ├── color.py
│   │   ├── image_to_knittingpattern.py
│   │   ├── load_and_dump.py
│   │   └── test/
│   │       ├── pictures/
│   │       │   └── conversion.tif
│   │       ├── test_AYABPNGBuilder.py
│   │       ├── test_SVGBuilder.py
│   │       ├── test_convert.py
│   │       ├── test_default_instruction_layout.py
│   │       ├── test_default_svgs.py
│   │       ├── test_images.py
│   │       ├── test_instruction_to_svg.py
│   │       ├── test_knittingpattern_to_png.py
│   │       ├── test_layout.py
│   │       ├── test_patterns/
│   │       │   ├── add and remove meshes.json
│   │       │   ├── block4x4.json
│   │       │   ├── cast_on_and_bind_off.json
│   │       │   ├── small-cafe.json
│   │       │   ├── split_up_and_add_rows.json
│   │       │   └── with hole.json
│   │       ├── test_png_to_knittingpattern.py
│   │       └── test_save_as_svg.py
│   ├── examples/
│   │   ├── Cafe.json
│   │   ├── Charlotte.json
│   │   ├── README.md
│   │   ├── all-instructions.json
│   │   ├── block4x4.json
│   │   ├── empty.json
│   │   ├── negative-rendering.json
│   │   └── new-knitting-pattern.py
│   ├── instructions/
│   │   ├── bo.json
│   │   ├── cdd.json
│   │   ├── co.json
│   │   ├── k2tog.json
│   │   ├── knit.json
│   │   ├── purl.json
│   │   ├── skp.json
│   │   └── yo.json
│   ├── test/
│   │   ├── conftest.py
│   │   ├── pattern/
│   │   │   ├── inheritance.json
│   │   │   ├── row_mapping_pattern.json
│   │   │   ├── row_removal_pattern.json
│   │   │   └── single_instruction.json
│   │   ├── test_add_and_remove_instructions.py
│   │   ├── test_change_row_mapping.py
│   │   ├── test_default_instructions.py
│   │   ├── test_dump_json.py
│   │   ├── test_dumper.py
│   │   ├── test_example_code.py
│   │   ├── test_example_rows.py
│   │   ├── test_examples.py
│   │   ├── test_id_collection.py
│   │   ├── test_instruction.py
│   │   ├── test_instruction_library.py
│   │   ├── test_instruction_row_inheritance.py
│   │   ├── test_instructions/
│   │   │   ├── recursion/
│   │   │   │   ├── test_instruction_3.json
│   │   │   │   └── test_instruction_4.json
│   │   │   ├── test_instruction_1.json
│   │   │   └── test_instruction_2.json
│   │   ├── test_knittingpattern.py
│   │   ├── test_load_instructions.py
│   │   ├── test_loader.py
│   │   ├── test_parsing.py
│   │   ├── test_row_instructions.py
│   │   ├── test_row_mapping.py
│   │   ├── test_row_meshes.py
│   │   ├── test_utilities.py
│   │   └── test_walk.py
│   ├── utils.py
│   └── walk.py
├── pylintrc
├── requirements.in
├── requirements.txt
├── setup.cfg
├── setup.py
├── test-requirements.in
└── test-requirements.txt

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

================================================
FILE: .codeclimate.yml
================================================
engines:
  duplication:
    enabled: true
    config:
      languages:
      - python
  fixme:
    enabled: true
  radon:
    enabled: true
  pep8:
    enabled: true
  radon: 
    enabled: true
ratings:
  paths:
  - "**.py"
exclude_paths: []


================================================
FILE: .gitignore
================================================
/.cache
/*.egg-info
/*.__pycache__
/dist
/build
*.pyc
*.coverage
/.eggs
*.swp
/.idea

================================================
FILE: .landscape.yaml
================================================
# https://docs.landscape.io/configuration.html
strictness: veryhigh
python-targets:
  - 3
pep8:
    full: true
doc-warnings: yes
test-warnings: yes
max-line-length: 79
autodetect: yes

================================================
FILE: .travis.yml
================================================
language: python
cache: pip
sudo: required
python:
- '3.3'
- '3.4'
- '3.5'
install:
# install the package
- PACKAGE_VERSION=`python setup.py --version`
- TAG_NAME=v$PACKAGE_VERSION
# install from the zip file to see if files were forgotten
- python setup.py sdist --dist-dir=dist --formats=zip
- ( cd dist ; pip install knittingpattern-${PACKAGE_VERSION}.zip )
# install the test requirements
- pip install -r test-requirements.txt
before_script:
# remove the build folder because it creates problems for py.test
- rm -rf build
# show the versions
- python setup.py --version
- py.test --version
- python setup.py requirements
- echo Package version $PACKAGE_VERSION with possible tag name $TAG_NAME
script:
# test with pep8
# add coverage for python 3.3 and above
- py.test --cov=knittingpattern --pep8
# test import form everywhere
- ( cd / && python -c "import knittingpattern;print(\"imported\")" )
# run tests from installation
- "( cd / && py.test --pyargs knittingpattern )"
# test that the tag represents the version
# https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
- ( if [ -n "$TRAVIS_TAG" ]; then if [ $TAG_NAME != $TRAVIS_TAG ]; then echo "This tag is for the wrong version. Got \"$TRAVIS_TAG\" expected \"$TAG_NAME\"."; exit 1; fi; fi; )
after_script:
# https://github.com/codeclimate/python-test-reporter
# set the environment variable CODECLIMATE_REPO_TOKEN in travis-ci settings
- codeclimate-test-reporter
before_deploy:
# create the documentation
- ( cd docs ; make html )
- pip install wheel
- python setup.py bdist_wheel
deploy:
# created with travis command line tool
# https://docs.travis-ci.com/user/deployment/pypi
# $ travis setup pypi
  provider: pypi
  user: niccokunzmann2
  password:
    secure: nqxnwagFphdLLJsjt4of/jMnLtsMtk8HqoPmENodEfaeue0A4ziIIm46tSBKdBqHURxuCFjj8siuaVCsXiZso/b4aJaIy08C3dcYltiLTfnYDJisicijEMg2wLNffJqiTN2+W6trHFJ7TzYz932jQEMmOC09mynt7LbP7RJOfqOGxvHiVL8D7I677xNLz+Kgu5R5FfZ9lzWcuBEbFTLffFcITeqVM+0yGJv9pZ+rud3RXl3qCAFYsG7SlHnzGuOyV/vWdAmfEuCvW+bs3oFS85Im4LiD1YTE5CQZhrwwGslncjOlWOAlrMuJzWmAG/6OTrIK7nIpI5gVlZdkesZQsx6JeR/22rVjkD9UcKj1R+7lzsC2X9Lh+vMRtxHJnDlW7clUA9+qw+TnvmR85UUhnmaaGtGJwZXDi0TP9wYmg3TaxoKKx5SnYDyFIq5kbVnSxSu1ng0qFMszGH1HYR350fEk8/so3IxdAbrHYbK5xeMv0vISJXdzIv/0U14lb4uB3agWf+SANQkrjYNx4BSE5zP1qj2HC2NsGwXdkl/8HjbTFe9Daj5nLTmGRL80GQ0BpRyJrT5wERRqozuWM1Jb1v6kgADhZhWAUryFlTZ+875He1CYXXoVSI59IER1ccK89NautsrF3mW/4o/WXCTzPDHtDkdavAvVPJc34oTmZgI=
  on:
    tags: true
    distributions: sdist bdist_wheel
    repo: fossasia/knittingpattern


================================================
FILE: CONTRIBUTING.rst
================================================
How to Contribute
=================

1. Read and agree to the `Developer Certificate of Origin
<DeveloperCertificateOfOrigin.txt>`_.


================================================
FILE: DeveloperCertificateOfOrigin.txt
================================================
Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.


================================================
FILE: LICENSE
================================================
GNU LESSER GENERAL PUBLIC LICENSE

Version 3, 29 June 2007

Copyright © 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
================================================
recursive-include knittingpattern *.py *.json *.svg
include *requirements.txt
include LICENSE
include knittingpattern/convert/test/pictures/*

================================================
FILE: README.rst
================================================
Knitting Pattern Library
===============

The knitting pattern library enables tailors, artisans and home knitters to use a common pattern for knitting machines and hand made knits.

.. image:: https://travis-ci.org/fossasia/knittingpattern.svg
   :target: https://travis-ci.org/fossasia/knittingpattern
   :alt: Build Status
   
.. image:: https://ci.appveyor.com/api/projects/status/c1983ovsc8thlhvi?svg=true
   :target: https://ci.appveyor.com/project/AllYarnsAreBeautiful/knittingpattern
   :alt: AppVeyor CI build status (Windows)
   
.. image:: https://codeclimate.com/github/fossasia/knittingpattern/badges/gpa.svg
   :target: https://codeclimate.com/github/fossasia/knittingpattern
   :alt: Code Climate

.. image:: https://codeclimate.com/github/fossasia/knittingpattern/badges/coverage.svg
   :target: https://codeclimate.com/github/fossasia/knittingpattern/coverage
   :alt: Test Coverage

.. image:: https://codeclimate.com/github/fossasia/knittingpattern/badges/issue_count.svg
   :target: https://codeclimate.com/github/fossasia/knittingpattern
   :alt: Issue Count

.. image:: https://badge.fury.io/py/knittingpattern.svg
   :target: https://pypi.python.org/pypi/knittingpattern
   :alt: Issue Count
   
.. image:: https://img.shields.io/pypi/dm/knittingpattern.svg
   :target: https://pypi.python.org/pypi/knittingpattern#downloads
   :alt: Downloads from pypi   

.. image:: https://readthedocs.org/projects/knittingpattern/badge/?version=latest
   :target: https://knittingpattern.readthedocs.org
   :alt: Read the Documentation

.. image:: https://landscape.io/github/fossasia/knittingpattern/master/landscape.svg?style=flat
   :target: https://landscape.io/github/fossasia/knittingpattern/master
   :alt: Code Health

.. image:: https://badge.waffle.io/fossasia/knittingpattern.svg?label=ready&title=issues%20ready
   :target: https://waffle.io/fossasia/knittingpattern
   :alt: Issues ready to work on


Installation and Documentation
===============
For installation instructions and more, `see the documentation
<http://knittingpattern.readthedocs.io/>`__.


================================================
FILE: appveyor.yml
================================================
# see https://packaging.python.org/appveyor/#adding-appveyor-support-to-your-project
clone_depth: 1
environment:

  PYPI_PASSWORD:
    secure: Gxrd9WI60wyczr9mHtiQHvJ45Oq0UyQZNrvUtKs2D5w=
  PYPI_USERNAME: niccokunzmann3

  matrix:

    # For Python versions available on Appveyor, see
    # http://www.appveyor.com/docs/installed-software#python
    # The list here is complete (excluding Python 2.6, which
    # isn't covered by this document) at the time of writing.

    - PYTHON: "C:\\Python33"
      UPLOAD_TO_PYPI: true
    - PYTHON: "C:\\Python34"
      UPLOAD_TO_PYPI: false
    - PYTHON: "C:\\Python35"
      UPLOAD_TO_PYPI: false
# 64 bit does not make a difference
#    - PYTHON: "C:\\Python33-x64"
#      DISTUTILS_USE_SDK: "1"
#    - PYTHON: "C:\\Python34-x64"
#      DISTUTILS_USE_SDK: "1"
#    - PYTHON: "C:\\Python35-x64"

install:
  # We need wheel installed to build wheels
  - "%PYTHON%\\python.exe -m pip install wheel"

build: off

test_script:
  # Put your test command here.
  # If you don't need to build C extensions on 64-bit Python 3.3 or 3.4,
  # you can remove "build.cmd" from the front of the command, as it's
  # only needed to support those cases.
  # Note that you must use the environment variable %PYTHON% to refer to
  # the interpreter you're using - Appveyor does not do anything special
  # to put the Python evrsion you want to use on PATH.
  - "%PYTHON%\\python.exe setup.py test"

after_test:
  # This step builds your wheels.
  # Again, you only need build.cmd if you're building C extensions for
  # 64-bit Python 3.3/3.4. And you need to use %PYTHON% to get the correct
  # interpreter
  - "%PYTHON%\\python.exe setup.py bdist_wheel"

artifacts:
  # bdist_wheel puts your built wheel in the dist directory
  - path: dist\*

on_success:
#  You can use this step to upload your artifacts to a public website.
#  See Appveyor's documentation for more details. Or you can simply
#  access your wheels from the Appveyor "artifacts" tab for your build.
  - echo "%APPVEYOR_REPO_TAG%"
  - echo "%APPVEYOR_REPO_TAG_NAME%"
  - echo "%UPLOAD_TO_PYPI%"
  - set HOME=.
  # in https://ci.appveyor.com/project/niccokunzmann/knittingpattern/settings/environment
  # set the variables for the python package index http://pypi.python.org/
  #   PYPI_USERNAME
  #   PYPI_PASSWORD
  - "IF %APPVEYOR_REPO_TAG% == true ( %PYTHON%\\python.exe -c \"import os;print('[distutils]\\r\\nindex-servers =\\r\\n    pypi\\r\\n\\r\\n[pypi]\\r\\nusername:{PYPI_USERNAME}\\r\\npassword:{PYPI_PASSWORD}\\r\\n'.format(**os.environ))\" > %HOME%\\.pypirc )"
  # upload to pypi
  # check for the tags
  # see http://www.appveyor.com/docs/branches#build-on-tags-github-and-gitlab-only
  - "IF %APPVEYOR_REPO_TAG% == true ( if \"%UPLOAD_TO_PYPI%\" == \"true\" ( FOR /F %%V IN ('%PYTHON%\\python.exe setup.py --version') DO ( IF \"v%%V\" == \"%APPVEYOR_REPO_TAG_NAME%\" ( %PYTHON%\\python.exe setup.py bdist_wininst upload || echo \"Error because the build is already uploaded.\" ) ELSE ( echo \"Invalid tag %APPVEYOR_REPO_TAG_NAME% should be v%%V.\" ) ) ) ELSE ( echo \"Upload skipped.\" ) ) ELSE ( echo \"Normal build without PyPi deployment.\" )"



================================================
FILE: dev-requirements.in
================================================
pip-tools
Sphinx-PyPI-upload3
autopep8


================================================
FILE: dev-requirements.txt
================================================
#
# This file is autogenerated by pip-compile
# To update, run:
#
#    pip-compile --output-file dev-requirements.txt dev-requirements.in
#
autopep8==1.2.4
click==6.6                # via pip-tools
first==2.0.1              # via pip-tools
pep8==1.7.0               # via autopep8
pip-tools==1.6.5
six==1.10.0               # via pip-tools
sphinx-pypi-upload3==0.2.2


================================================
FILE: docs/DevelopmentSetup.rst
================================================
.. _development-setup:

Development Setup
=================

Make sure that you have the :ref:`repository installed
<installation-repository>`.

.. _development-setup-requirements:

Install Requirements
--------------------

To install all requirements for the development setup, execute

.. code:: bash

    pip install --upgrade -r requirements.txt -r test-requirements.txt -r dev-requirements.txt

Sphinx Documentation Setup
--------------------------

Sphinx was setup using `the tutorial from readthedocs
<http://read-the-docs.readthedocs.io/en/latest/getting_started.html>`__.
It should be already setup if you completed :ref:`the previous step
<development-setup-requirements>`.

Further reading:

- `domains <http://www.sphinx-doc.org/en/stable/domains.html>`__

With Notepad++ under Windows, you can run the `make_html.bat
<https://github.com/fossasia/knittingpattern/blob/master/docs/make_html.bat>`__ file in the
``docs`` directory to create the documentation and show undocumented code.

Code Climate
------------

To install the code climate command line interface (cli), read about it in
their github `repository <https://github.com/codeclimate/codeclimate>`__
You need docker to be installed. Under Linux you can execute this in the 
Terminal to install docker:

.. code:: bash
    
    wget -qO- https://get.docker.com/ | sh
    sudo usermod -aG docker $USER
    
Then, log in and out. Then, you can install the command line interface:

.. code:: bash

    wget -qO- https://github.com/codeclimate/codeclimate/archive/master.tar.gz | tar xvz
    cd codeclimate-* && sudo make install

Then, go to the knittingpattern repository and analyze it.

.. code:: bash

    codeclimate analyze
    
Version Pinning
---------------

We use version pinning, described in `this blog post (outdated)
<http://nvie.com/posts/pin-your-packages/>`__.
Also read the `current version
<https://github.com/nvie/pip-tools>`__ for how to set up.

After installation you can run

.. code:: bash

    pip install -r requirements.in -r test-requirements.in -r dev-requirements.in
    pip-compile --output-file requirements.txt requirements.in
    pip-compile --output-file test-requirements.txt test-requirements.in
    pip-compile --output-file dev-requirements.txt dev-requirements.in
    pip-sync requirements.txt dev-requirements.txt test-requirements.txt
    pip install --upgrade -r requirements.txt -r test-requirements.txt -r dev-requirements.txt

``pip-sync`` uninstalls every package you do not need and 
writes the fix package versions to the requirements files.

Continuous Integration to Pypi
------------------------------

Before you put something on `Pypi
<https://pypi.python.org/pypi/knittingpattern>`__, ensure the following:

1. The version is in the master branch on github.
2. The tests run by travis-ci run successfully.

Pypi is automatically deployed by travis. `See here
<https://docs.travis-ci.com/user/deployment/pypi>`__.
To upload new versions, tag them with git and push them.

.. code:: bash

  setup.py tag_and_deploy

The tag shows up as a `travis build
<https://travis-ci.org/fossasia/knittingpattern/builds>`__.
If the build succeeds, it is automatically deployed to `Pypi
<https://pypi.python.org/pypi/knittingpattern>`__.

Manual Upload to the Python Package Index
-----------------------------------------


However, here you can see how to upload this package manually.

Version
~~~~~~~

Throughout this chapter, ``<new_version>`` refers to a a string of the form ``[0-9]+\.[0-9]+\.[0-9]+[ab]?`` or ``<MAYOR>.<MINOR>.<STEP>[<MATURITY>]`` where ``<MAYOR>``, ``<MINOR>`` and, ``<STEP>`` represent numbers and ``<MATURITY>`` can be a letter to indicate how mature the release is.

1. Create a new branch for the version.

.. code:: bash

  git checkout -b <new_version>

2. Increase the ``__version__`` in `__init__.py <knittingpattern/__init__.py#L3>`__

   - no letter at the end means release
   - ``b`` in the end means Beta
   - ``a`` in the end means Alpha

3. Commit and upload this version.

.. _commit:

.. code:: bash
  
  git add knittingpattern/__init__.py
  git commit -m "version <new_version>"
  git push origin <new_version>

4. Create a pull-request.

5. Wait for `travis-ci <https://travis-ci.org/fossasia/knittingpattern>`__ to pass the tests.

6. Merge the pull-request.
7. Checkout the master branch and pull the changes from the commit_.

.. code:: bash

  git checkout master
  git pull

8. Tag the version at the master branch with a ``v`` in the beginning and push it to github.

.. code:: bash

  git tag v<new_version>
  git push origin v<new_version>

9. Upload_ the code to Pypi.
  

Upload
~~~~~~

.. Upload:

First ensure all tests are running:

.. code:: bash

    setup.py pep8


From `docs.python.org
<https://docs.python.org/3.1/distutils/uploading.html>`__:

.. code:: bash

    setup.py sdist bdist_wininst upload register
    
Classifiers
-----------

You can find all Pypi classifiers `here
<http://pypi.python.org/pypi?%3Aaction=list_classifiers>`_.




================================================
FILE: docs/FileFormatSpecification.rst
================================================
.. _FileFormatSpecification:

Knitting Pattern File Format Specification
==========================================

For the words see `the glossary
<https://github.com/AllYarnsAreBeautiful/ayab-desktop/wiki/Glossary>`__.

Design Decisions
----------------

Concerns:

- We can never implement everything that is possible with knitting. We must therefore allow instructions to be arbitrary.
- We can not use a grid as a basis. This does not reflect if you split the work and make i.e. two big legs
- Knitting can be done on the right and on the wrong side. The same result can be achived when knitting in both directions. 

Assumptions
-----------

- we start from bottom right
- default instruction (`see
  <https://github.com/AllYarnsAreBeautiful/ayab-desktop/wiki/2016-05-25---Knitting-pattern>`_)
  
  .. code:: json
    
    {
      "type" : "knit", 
    }
    {
      "type" : "ktog tbl", # identifier
      "count" : 2
    }
    
- default connection

  .. code:: json
   
      {
        "start" : 0,
      }
        
- ``"id"`` can point to an object.



================================================
FILE: docs/Installation.rst
================================================
.. _installation:

knittingpattern Installation Instructions
=========================================

Package installation from Pypi
------------------------------

The knittingpattern library requires `Python 3 <https://www.python.org/>`__.
It can be installed form the `Python Package Index
<https://pypi.python.org/pypi/knittingpattern>`__.

Windows
~~~~~~~

Install it with a specific python version under windows:

.. code:: bash

    py -3 -m pip --no-cache-dir install --upgrade knittingpattern

Test the installed version:

.. code:: bash

    py -3 -m pytest --pyargs knittingpattern

Linux
~~~~~ 

To install the version from the python package index, you can use your terminal and execute this under Linux:

.. code:: shell
  
  sudo python3 -m pip --no-cache-dir install --upgrade knittingpattern

test the installed version:

.. code:: shell
  
  python3 -m pytest --pyargs knittingpattern

.. _installation-repository:

Installation from Repository
----------------------------

You can setup the development version under Windows and Linux.

.. _installation-repository-linux:

Linux
~~~~~

If you wish to get latest source version running, you can check out the repository and install it manually.

.. code:: bash

  git clone https://github.com/fossasia/knittingpattern.git
  cd knittingpattern
  sudo python3 -m pip install --upgrade pip
  sudo python3 -m pip install -r requirements.txt
  sudo python3 -m pip install -r test-requirements.txt
  py.test

To also make it importable for other libraries, you can link it into the site-packages folder this way:

.. code:: bash

  sudo python3 setup.py link

.. _installation-repository-windows:

Windows
~~~~~~~

Same as under :ref:`installation-repository-linux` but you need to replace
``sudo python3`` with ``py -3``. This also counts for the following
documentation.


================================================
FILE: docs/Makefile
================================================
# Makefile for Sphinx documentation
#

# You can set these variables from the command line.
SPHINXOPTS    =
SPHINXBUILD   = sphinx-build
PAPER         =
BUILDDIR      = ../build
DOCDIR        = .

# Internal variables.
PAPEROPT_a4     = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(DOCDIR)
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(DOCDIR)

.PHONY: help
help:
	@echo "Please use \`make <target>' where <target> is one of"
	@echo "  html       to make standalone HTML files"
	@echo "  dirhtml    to make HTML files named index.html in directories"
	@echo "  singlehtml to make a single large HTML file"
	@echo "  pickle     to make pickle files"
	@echo "  json       to make JSON files"
	@echo "  htmlhelp   to make HTML files and a HTML help project"
	@echo "  qthelp     to make HTML files and a qthelp project"
	@echo "  applehelp  to make an Apple Help Book"
	@echo "  devhelp    to make HTML files and a Devhelp project"
	@echo "  epub       to make an epub"
	@echo "  epub3      to make an epub3"
	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
	@echo "  text       to make text files"
	@echo "  man        to make manual pages"
	@echo "  texinfo    to make Texinfo files"
	@echo "  info       to make Texinfo files and run them through makeinfo"
	@echo "  gettext    to make PO message catalogs"
	@echo "  changes    to make an overview of all changed/added/deprecated items"
	@echo "  xml        to make Docutils-native XML files"
	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
	@echo "  linkcheck  to check all external links for integrity"
	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
	@echo "  coverage   to run coverage check of the documentation (if enabled)"
	@echo "  dummy      to check syntax errors of document sources"

.PHONY: clean
clean:
	rm -rf $(BUILDDIR)/*

.PHONY: html
html:
	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

.PHONY: dirhtml
dirhtml:
	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."

.PHONY: singlehtml
singlehtml:
	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
	@echo
	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."

.PHONY: pickle
pickle:
	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
	@echo
	@echo "Build finished; now you can process the pickle files."

.PHONY: json
json:
	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
	@echo
	@echo "Build finished; now you can process the JSON files."

.PHONY: htmlhelp
htmlhelp:
	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
	@echo
	@echo "Build finished; now you can run HTML Help Workshop with the" \
	      ".hhp project file in $(BUILDDIR)/htmlhelp."

.PHONY: qthelp
qthelp:
	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
	@echo
	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/knittingpattern.qhcp"
	@echo "To view the help file:"
	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/knittingpattern.qhc"

.PHONY: applehelp
applehelp:
	$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
	@echo
	@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
	@echo "N.B. You won't be able to view it unless you put it in" \
	      "~/Library/Documentation/Help or install it in your application" \
	      "bundle."

.PHONY: devhelp
devhelp:
	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
	@echo
	@echo "Build finished."
	@echo "To view the help file:"
	@echo "# mkdir -p $$HOME/.local/share/devhelp/knittingpattern"
	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/knittingpattern"
	@echo "# devhelp"

.PHONY: epub
epub:
	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
	@echo
	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."

.PHONY: epub3
epub3:
	$(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
	@echo
	@echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."

.PHONY: latex
latex:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo
	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
	@echo "Run \`make' in that directory to run these through (pdf)latex" \
	      "(use \`make latexpdf' here to do that automatically)."

.PHONY: latexpdf
latexpdf:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through pdflatex..."
	$(MAKE) -C $(BUILDDIR)/latex all-pdf
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

.PHONY: latexpdfja
latexpdfja:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through platex and dvipdfmx..."
	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

.PHONY: text
text:
	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
	@echo
	@echo "Build finished. The text files are in $(BUILDDIR)/text."

.PHONY: man
man:
	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
	@echo
	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."

.PHONY: texinfo
texinfo:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo
	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
	@echo "Run \`make' in that directory to run these through makeinfo" \
	      "(use \`make info' here to do that automatically)."

.PHONY: info
info:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo "Running Texinfo files through makeinfo..."
	make -C $(BUILDDIR)/texinfo info
	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."

.PHONY: gettext
gettext:
	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
	@echo
	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."

.PHONY: changes
changes:
	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
	@echo
	@echo "The overview file is in $(BUILDDIR)/changes."

.PHONY: linkcheck
linkcheck:
	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
	@echo
	@echo "Link check complete; look for any errors in the above output " \
	      "or in $(BUILDDIR)/linkcheck/output.txt."

.PHONY: doctest
doctest:
	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
	@echo "Testing of doctests in the sources finished, look at the " \
	      "results in $(BUILDDIR)/doctest/output.txt."

.PHONY: coverage
coverage:
	$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
	@echo "Testing of coverage in the sources finished, look at the " \
	      "results in $(BUILDDIR)/coverage/python.txt."

.PHONY: xml
xml:
	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
	@echo
	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."

.PHONY: pseudoxml
pseudoxml:
	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
	@echo
	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

.PHONY: dummy
dummy:
	$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
	@echo
	@echo "Build finished. Dummy builder generates no files."


================================================
FILE: docs/_static/.gitignore
================================================
# This file is used so the folder turns up in git.

================================================
FILE: docs/_templates/.gitignore
================================================
# This file is used so the folder turns up in git.

================================================
FILE: docs/conf.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# knittingpattern documentation build configuration file, created by
# sphinx-quickstart on Thu Jun 23 09:49:51 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
HERE = os.path.dirname(__file__)
sys.path.insert(0, os.path.abspath(os.path.join(HERE, '..')))

# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.doctest',
    'sphinx.ext.intersphinx',
    'sphinx.ext.todo',
    'sphinx.ext.coverage',
    'sphinx.ext.mathjax',
    'sphinx.ext.ifconfig',
    'sphinx.ext.viewcode',
    'sphinx.ext.githubpages',
    'sphinx_paramlinks',  # https://pypi.python.org/pypi/sphinx-paramlinks/
                          # http://stackoverflow.com/a/20845306/1320237
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'

# The encoding of source files.
#
# source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = 'knittingpattern'
copyright = '2016, AllYarnsAreBeautiful & FOSSASIA'
author = 'AllYarnsAreBeautiful & FOSSASIA'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
# version = '0.0'
# The full version, including alpha/beta/rc tags.
# release = '8'
project_version = __import__(project).__version__
version, release = project_version.rsplit(".", 1)

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#
# today = ''
#
# Else, today_fmt is used as the format for a strftime call.
#
# today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []

# The reST default role (used for this markup: `text`) to use for all
# documents.
#
# default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#
add_function_parentheses = True

# http://stackoverflow.com/q/5599254/1320237
# use the doc string in the init method
# autoclass_content = 'both'

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#
# add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#
# show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []

# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False

# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True


# -- Options for HTML output ----------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#

# from https://github.com/rtfd/readthedocs.org/blob/master/docs/conf.py
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd:  # only import and set the theme if we're building docs locally
    import sphinx_rtd_theme
    html_theme = 'sphinx_rtd_theme'
    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []

# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
#
html_title = project + " " + project_version

# A shorter title for the navigation bar.  Default is the same as html_title.
#
html_short_title = project

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#
# html_logo = None
# TODO

# The name of an image file (relative to this directory) to use as a favicon of
# the docs.  This file should be a Windows icon file (.ico) being 16x16 or
# 32x32 pixels large.
#
# html_favicon = None
# TODO

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#
# html_extra_path = []

# If not None, a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format.
# The empty string is equivalent to '%b %d, %Y'.
#
# html_last_updated_fmt = None

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#
# html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#
# html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#
# html_additional_pages = {}

# If false, no module index is generated.
#
# html_domain_indices = True

# If false, no index is generated.
#
# html_use_index = True

# If true, the index is split into individual pages for each letter.
#
# html_split_index = False

# If true, links to the reST sources are added to the pages.
#
html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#
# html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#
html_show_copyright = False

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#
# html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None

# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
#   'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
#   'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh'
#
html_search_language = 'en'

# A dictionary with options for the search language support, empty by default.
# 'ja' uses this config value.
# 'zh' user can custom change `jieba` dictionary path.
#
# html_search_options = {'type': 'default'}

# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#
# html_search_scorer = 'scorer.js'

# Output file base name for HTML help builder.
htmlhelp_basename = 'knittingpatterndoc'

# -- Options for LaTeX output ---------------------------------------------

latex_elements = {
     # The paper size ('letterpaper' or 'a4paper').
     #
     # 'papersize': 'letterpaper',

     # The font size ('10pt', '11pt' or '12pt').
     #
     # 'pointsize': '10pt',

     # Additional stuff for the LaTeX preamble.
     #
     # 'preamble': '',

     # Latex figure (float) alignment
     #
     # 'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
    (master_doc, 'knittingpattern.tex', 'knittingpattern Documentation',
     'AllYarnsAreBeautiful & FOSSASIA', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#
# latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#
# latex_use_parts = False

# If true, show page references after internal links.
#
# latex_show_pagerefs = False

# If true, show URL addresses after external links.
#
# latex_show_urls = False

# Documents to append as an appendix to all manuals.
#
# latex_appendices = []

# If false, no module index is generated.
#
# latex_domain_indices = True


# -- Options for manual page output ---------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    (master_doc, project, project + ' Documentation',
     [author], 1)
]

# If true, show URL addresses after external links.
#
# man_show_urls = False


# -- Options for Texinfo output -------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    (master_doc, project, project + ' Documentation',
     author, project, 'One line description of project.',  # TODO
     'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#
# texinfo_appendices = []

# If false, no module index is generated.
#
# texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#
texinfo_show_urls = 'footnote'

# If true, do not generate a @detailmenu in the "Top" node's menu.
#
# texinfo_no_detailmenu = False


# -- Options for Epub output ----------------------------------------------

# Bibliographic Dublin Core info.
epub_title = project
epub_author = author
epub_publisher = author
epub_copyright = copyright

# The basename for the epub file. It defaults to the project name.
# epub_basename = project

# The HTML theme for the epub output. Since the default themes are not
# optimized for small screen space, using the same theme for HTML and epub
# output is usually not wise. This defaults to 'epub', a theme designed to save
# visual space.
#
# epub_theme = 'epub'

# The language of the text. It defaults to the language option
# or 'en' if the language is not set.
#
# epub_language = ''

# The scheme of the identifier. Typical schemes are ISBN or URL.
# epub_scheme = ''

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''

# A unique identification for the text.
#
# epub_uid = ''

# A tuple containing the cover image and cover page html template filenames.
#
# epub_cover = ()

# A sequence of (type, uri, title) tuples for the guide element of content.opf.
#
# epub_guide = ()

# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#
# epub_pre_files = []

# HTML files that should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#
# epub_post_files = []

# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']

# The depth of the table of contents in toc.ncx.
#
# epub_tocdepth = 3

# Allow duplicate toc entries.
#
# epub_tocdup = True

# Choose between 'default' and 'includehidden'.
#
# epub_tocscope = 'default'

# Fix unsupported image types using the Pillow.
#
# epub_fix_images = False

# Scale large images.
#
# epub_max_image_width = 0

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#
# epub_show_urls = 'inline'

# If false, no index is generated.
#
# epub_use_index = True


# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
    "https://docs.python.org/3/": None,
    "http://observablelist.readthedocs.io/en/latest/": None,
    "https://kivy.org/docs/": None}


================================================
FILE: docs/index.rst
================================================
.. knittingpattern documentation master file, created by
   sphinx-quickstart on Thu Jun 23 09:49:51 2016.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Welcome to knittingpattern's documentation!
===========================================

Contents:

.. toctree::
   :maxdepth: 2

   Installation
   FileFormatSpecification
   DevelopmentSetup
   reference/index


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`



================================================
FILE: docs/make.bat
================================================
@ECHO OFF

REM Command file for Sphinx documentation

set DOCDIR=.

if "%SPHINXBUILD%" == "" (
	set SPHINXBUILD=sphinx-build
)
set BUILDDIR=../build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %DOCDIR%
set I18NSPHINXOPTS=%SPHINXOPTS% %DOCDIR%
if NOT "%PAPER%" == "" (
	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
	set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)

if "%1" == "" goto help

if "%1" == "help" (
	:help
	echo.Please use `make ^<target^>` where ^<target^> is one of
	echo.  html       to make standalone HTML files
	echo.  dirhtml    to make HTML files named index.html in directories
	echo.  singlehtml to make a single large HTML file
	echo.  pickle     to make pickle files
	echo.  json       to make JSON files
	echo.  htmlhelp   to make HTML files and a HTML help project
	echo.  qthelp     to make HTML files and a qthelp project
	echo.  devhelp    to make HTML files and a Devhelp project
	echo.  epub       to make an epub
	echo.  epub3      to make an epub3
	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
	echo.  text       to make text files
	echo.  man        to make manual pages
	echo.  texinfo    to make Texinfo files
	echo.  gettext    to make PO message catalogs
	echo.  changes    to make an overview over all changed/added/deprecated items
	echo.  xml        to make Docutils-native XML files
	echo.  pseudoxml  to make pseudoxml-XML files for display purposes
	echo.  linkcheck  to check all external links for integrity
	echo.  doctest    to run all doctests embedded in the documentation if enabled
	echo.  coverage   to run coverage check of the documentation if enabled
	echo.  dummy      to check syntax errors of document sources
	goto end
)

if "%1" == "clean" (
	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
	del /q /s %BUILDDIR%\*
	goto end
)


REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 1>NUL 2>NUL
if errorlevel 9009 goto sphinx_python
goto sphinx_ok

:sphinx_python

set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
	echo.
	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
	echo.installed, then set the SPHINXBUILD environment variable to point
	echo.to the full path of the 'sphinx-build' executable. Alternatively you
	echo.may add the Sphinx directory to PATH.
	echo.
	echo.If you don't have Sphinx installed, grab it from
	echo.http://sphinx-doc.org/
	exit /b 1
)

:sphinx_ok


if "%1" == "html" (
	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
	goto end
)

if "%1" == "dirhtml" (
	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
	goto end
)

if "%1" == "singlehtml" (
	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
	goto end
)

if "%1" == "pickle" (
	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; now you can process the pickle files.
	goto end
)

if "%1" == "json" (
	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; now you can process the JSON files.
	goto end
)

if "%1" == "htmlhelp" (
	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
	goto end
)

if "%1" == "qthelp" (
	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\knittingpattern.qhcp
	echo.To view the help file:
	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\knittingpattern.ghc
	goto end
)

if "%1" == "devhelp" (
	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished.
	goto end
)

if "%1" == "epub" (
	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The epub file is in %BUILDDIR%/epub.
	goto end
)

if "%1" == "epub3" (
	%SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The epub3 file is in %BUILDDIR%/epub3.
	goto end
)

if "%1" == "latex" (
	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
	goto end
)

if "%1" == "latexpdf" (
	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
	cd %BUILDDIR%/latex
	make all-pdf
	cd %~dp0
	echo.
	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
	goto end
)

if "%1" == "latexpdfja" (
	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
	cd %BUILDDIR%/latex
	make all-pdf-ja
	cd %~dp0
	echo.
	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
	goto end
)

if "%1" == "text" (
	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The text files are in %BUILDDIR%/text.
	goto end
)

if "%1" == "man" (
	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The manual pages are in %BUILDDIR%/man.
	goto end
)

if "%1" == "texinfo" (
	%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
	goto end
)

if "%1" == "gettext" (
	%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
	goto end
)

if "%1" == "changes" (
	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
	if errorlevel 1 exit /b 1
	echo.
	echo.The overview file is in %BUILDDIR%/changes.
	goto end
)

if "%1" == "linkcheck" (
	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
	if errorlevel 1 exit /b 1
	echo.
	echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
	goto end
)

if "%1" == "doctest" (
	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
	if errorlevel 1 exit /b 1
	echo.
	echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
	goto end
)

if "%1" == "coverage" (
	%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
	if errorlevel 1 exit /b 1
	echo.
	echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
	goto end
)

if "%1" == "xml" (
	%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The XML files are in %BUILDDIR%/xml.
	goto end
)

if "%1" == "pseudoxml" (
	%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
	goto end
)

if "%1" == "dummy" (
	%SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy
	if errorlevel 1 exit /b 1
	echo.
	echo.Build finished. Dummy builder generates no files.
	goto end
)

:end


================================================
FILE: docs/make_html.bat
================================================
@echo off

REM 
REM This is a shortcut for notepad++
REM You can press F5 and use this as command to update the html of the docs. 
REM 

cd "%~dp0"

call make html
call make coverage

py -c "print(open('../build/coverage/Python.txt').read())"

py -c "import time;time.sleep(10);print('exit')"

================================================
FILE: docs/reference/index.rst
================================================
Reference
=========

.. toctree::
   :maxdepth: 2

   knittingpattern/index
   knittingpattern/convert/index
   knittingpattern/Dumper/index


================================================
FILE: docs/reference/knittingpattern/Dumper/FileWrapper.rst
================================================

.. py:currentmodule:: knittingpattern.Dumper.FileWrapper

:py:mod:`FileWrapper` Module
============================

.. automodule:: knittingpattern.Dumper.FileWrapper
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Dumper/file.rst
================================================

.. py:currentmodule:: knittingpattern.Dumper.file

:py:mod:`file` Module
=====================

.. automodule:: knittingpattern.Dumper.file
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Dumper/index.rst
================================================
The ``knittingpattern.Dumper`` Module Reference
===============================================

.. toctree::
   :maxdepth: 2
   
   init
   file
   FileWrapper
   json
   svg
   xml


================================================
FILE: docs/reference/knittingpattern/Dumper/init.rst
================================================

.. py:currentmodule:: knittingpattern.Dumper

:py:mod:`Dumper` Module
=======================

.. automodule:: knittingpattern.Dumper
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Dumper/json.rst
================================================

.. py:currentmodule:: knittingpattern.Dumper.json

:py:mod:`json` Module
=====================

.. automodule:: knittingpattern.Dumper.json
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Dumper/svg.rst
================================================

.. py:currentmodule:: knittingpattern.Dumper.svg

:py:mod:`svg` Module
====================

.. automodule:: knittingpattern.Dumper.svg
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Dumper/xml.rst
================================================

.. py:currentmodule:: knittingpattern.Dumper.xml

:py:mod:`xml` Module
====================

.. automodule:: knittingpattern.Dumper.xml
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/IdCollection.rst
================================================

.. py:currentmodule:: knittingpattern.IdCollection

:py:mod:`IdCollection` Module
=============================

.. automodule:: knittingpattern.IdCollection
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Instruction.rst
================================================

.. py:currentmodule:: knittingpattern.Instruction

:py:mod:`Instruction` Module
============================

.. automodule:: knittingpattern.Instruction
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/InstructionLibrary.rst
================================================

.. py:currentmodule:: knittingpattern.InstructionLibrary

:py:mod:`InstructionLibrary` Module
===================================

.. automodule:: knittingpattern.InstructionLibrary
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/KnittingPattern.rst
================================================

.. py:currentmodule:: knittingpattern.KnittingPattern

:py:mod:`KnittingPattern` Module
================================

.. automodule:: knittingpattern.KnittingPattern
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/KnittingPatternSet.rst
================================================

.. py:currentmodule:: knittingpattern.KnittingPatternSet

:py:mod:`KnittingPatternSet` Module
===================================

.. automodule:: knittingpattern.KnittingPatternSet
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Loader.rst
================================================

.. py:currentmodule:: knittingpattern.Loader

:py:mod:`Loader` Module
=======================

.. automodule:: knittingpattern.Loader
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Mesh.rst
================================================

.. py:currentmodule:: knittingpattern.Mesh

:py:mod:`Mesh` Module
=====================

.. automodule:: knittingpattern.Mesh
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Parser.rst
================================================

.. py:currentmodule:: knittingpattern.Parser

:py:mod:`Parser` Module
=======================

.. automodule:: knittingpattern.Parser
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/ParsingSpecification.rst
================================================

.. py:currentmodule:: knittingpattern.ParsingSpecification

:py:mod:`ParsingSpecification` Module
=====================================

.. automodule:: knittingpattern.ParsingSpecification
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Prototype.rst
================================================

.. py:currentmodule:: knittingpattern.Prototype

:py:mod:`Prototype` Module
==========================

.. automodule:: knittingpattern.Prototype
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/Row.rst
================================================

.. py:currentmodule:: knittingpattern.Row

:py:mod:`Row` Module
====================

.. automodule:: knittingpattern.Row
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/AYABPNGBuilder.rst
================================================

.. py:currentmodule:: knittingpattern.convert.AYABPNGBuilder

:py:mod:`AYABPNGBuilder` Module
===============================

.. automodule:: knittingpattern.convert.AYABPNGBuilder
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/AYABPNGDumper.rst
================================================

.. py:currentmodule:: knittingpattern.convert.AYABPNGDumper

:py:mod:`AYABPNGDumper` Module
==============================

.. automodule:: knittingpattern.convert.AYABPNGDumper
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/InstructionSVGCache.rst
================================================

.. py:currentmodule:: knittingpattern.convert.InstructionSVGCache

:py:mod:`InstructionSVGCache` Module
====================================

.. automodule:: knittingpattern.convert.InstructionSVGCache
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/InstructionToSVG.rst
================================================

.. py:currentmodule:: knittingpattern.convert.InstructionToSVG

:py:mod:`InstructionToSVG` Module
=================================

.. automodule:: knittingpattern.convert.InstructionToSVG
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/KnittingPatternToSVG.rst
================================================

.. py:currentmodule:: knittingpattern.convert.KnittingPatternToSVG

:py:mod:`KnittingPatternToSVG` Module
=====================================

.. automodule:: knittingpattern.convert.KnittingPatternToSVG
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/Layout.rst
================================================

.. py:currentmodule:: knittingpattern.convert.Layout

:py:mod:`Layout` Module
=======================

.. automodule:: knittingpattern.convert.Layout
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/SVGBuilder.rst
================================================

.. py:currentmodule:: knittingpattern.convert.SVGBuilder

:py:mod:`SVGBuilder` Module
===========================

.. automodule:: knittingpattern.convert.SVGBuilder
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/color.rst
================================================

.. py:currentmodule:: knittingpattern.convert.color

:py:mod:`color` Module
======================

.. automodule:: knittingpattern.convert.color
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/image_to_knittingpattern.rst
================================================

.. py:currentmodule:: knittingpattern.convert.image_to_knittingpattern

:py:mod:`image_to_knittingpattern` Module
=========================================

.. automodule:: knittingpattern.convert.image_to_knittingpattern
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/index.rst
================================================
The ``knittingpattern.convert`` Module Reference
================================================

.. toctree::
   :maxdepth: 2

   init
   color
   AYABPNGBuilder
   AYABPNGDumper
   image_to_knittingpattern
   InstructionToSVG
   InstructionSVGCache
   KnittingPatternToSVG
   Layout
   load_and_dump
   SVGBuilder


================================================
FILE: docs/reference/knittingpattern/convert/init.rst
================================================

.. py:currentmodule:: knittingpattern.convert

:py:mod:`convert` Module
========================

.. automodule:: knittingpattern.convert
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/convert/load_and_dump.rst
================================================

.. py:currentmodule:: knittingpattern.convert.load_and_dump

:py:mod:`load_and_dump` Module
==============================

.. automodule:: knittingpattern.convert.load_and_dump
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/index.rst
================================================
The ``knittingpattern`` Module Reference
========================================

.. toctree::
   :maxdepth: 2

   init
   IdCollection
   Instruction
   InstructionLibrary
   KnittingPattern
   KnittingPatternSet
   Loader
   Mesh
   Parser
   ParsingSpecification
   Prototype
   Row
   utils
   walk


================================================
FILE: docs/reference/knittingpattern/init.rst
================================================

.. py:currentmodule:: knittingpattern

:py:mod:`knittingpattern` Module
================================

.. automodule:: knittingpattern
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/utils.rst
================================================

.. py:currentmodule:: knittingpattern.utils

:py:mod:`utils` Module
======================

.. automodule:: knittingpattern.utils
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/reference/knittingpattern/walk.rst
================================================

.. py:currentmodule:: knittingpattern.walk

:py:mod:`walk` Module
=====================

.. automodule:: knittingpattern.walk
   :show-inheritance:
   :members:
   :special-members:



================================================
FILE: docs/test/test_docs.py
================================================
import os


def absjoin(*args):
    """
    :return: an absolute path to the joined arguments
    :param args: the parts of the path to join
    """
    return os.path.abspath(os.path.join(*args))

PACKAGE = "knittingpattern"

HERE = absjoin(os.path.dirname(__file__))
DOCS_DIRECTORY = absjoin(HERE, "..")
PACKAGE_LOCATION = absjoin(DOCS_DIRECTORY, "..")
PACKAGE_ROOT = absjoin(PACKAGE_LOCATION, PACKAGE)
PACKAGE_DOCUMENTATION = absjoin(HERE, "..", "reference")
BUILD_DIRECTORY = absjoin(PACKAGE_LOCATION, "build")
COVERAGE_DIRECTORY = absjoin(BUILD_DIRECTORY, "coverage")
PYTHON_COVERAGE_FILE = absjoin(COVERAGE_DIRECTORY, "python.txt")

__all__ = ["PACKAGE", "HERE", "DOCS_DIRECTORY", "PACKAGE_LOCATION",
           "PACKAGE_ROOT", "PACKAGE_DOCUMENTATION", "BUILD_DIRECTORY",
           "COVERAGE_DIRECTORY", "PYTHON_COVERAGE_FILE"]


================================================
FILE: docs/test/test_documentation_sources_exist.py
================================================
#!/usr/bin/python3
"""Test the coverage of documentation.

No function shall be left out by the documentation.
Run this module to create the missing documentation files.

"""
from test_docs import PACKAGE_LOCATION, PACKAGE, PACKAGE_DOCUMENTATION, \
    PACKAGE_ROOT
import pytest
from collections import namedtuple
import os


def relative_module_path(absolute_path):
    relative_path = absolute_path[len(PACKAGE_LOCATION):]
    if not relative_path.startswith(PACKAGE):
        # remove /
        relative_path = relative_path[1:]
    assert relative_path.startswith(PACKAGE)
    return relative_path


def module_name_and_doc(relative_path):
    assert relative_path.startswith(PACKAGE)
    file, ext = os.path.splitext(relative_path)
    assert ext == ".py"
    names = []
    while file:
        file, name = os.path.split(file)
        names.insert(0, name)
    assert names
    doc = names[:-1] + [names[-1].replace("__", "") + ".rst"]
    doc_file = os.path.join(PACKAGE_DOCUMENTATION, *doc)
    if names[-1] == "__init__":
        del names[-1]
    return ".".join(names), doc_file


Module = namedtuple("Module", ["absolute_path", "path", "name", "doc_file",
                               "lines", "title"])
MODULES = []


def add_module(absolute_path):
    relative_path = relative_module_path(absolute_path)
    name, doc_path = module_name_and_doc(relative_path)
    if os.path.isfile(doc_path):
        with open(doc_path) as file:
            lines = file.readlines()
    else:
        lines = []
    relative_name = name.rsplit(".", 1)[-1]
    title = ":py:mod:`{}` Module".format(relative_name)
    MODULES.append(Module(absolute_path, relative_path, name, doc_path, lines,
                          title))


for dirpath, dirnames, filenames in os.walk(PACKAGE_ROOT):
    if "__init__.py" not in filenames:
        # only use module content
        continue
    for filename in filenames:
        if filename.endswith(".py"):
            add_module(os.path.join(dirpath, filename))


CREATE_MODULE_MESSAGE = "You can execute {} to create the missing "\
                        "documentation file.".format(__file__)


@pytest.mark.parametrize('module', MODULES)
def test_module_has_a_documentation_file(module):
    assert os.path.isfile(module.doc_file), CREATE_MODULE_MESSAGE


@pytest.mark.parametrize('module', MODULES)
def test_documentation_references_module(module):
    # assert module.lines[0].strip() == ".. py:module:: " + module.name
    assert module.lines[1].strip() == ".. py:currentmodule:: " + module.name


@pytest.mark.parametrize('module', MODULES)
def test_documentation_has_proper_title(module):
    assert module.lines[2].strip() == ""
    assert module.lines[3].strip() == module.title
    assert module.lines[4].strip() == "=" * len(module.title)


def create_new_module_documentation():
    """Create documentation so it fits the tests."""
    for module in MODULES:
        if not os.path.isfile(module.doc_file):
            directory = os.path.dirname(module.doc_file)
            os.makedirs(directory, exist_ok=True)
            with open(module.doc_file, "w") as file:
                write = file.write
                write("\n")  # .. py:module:: " + module.name + "\n")
                write(".. py:currentmodule:: " + module.name + "\n")
                write("\n")
                write(module.title + "\n")
                write("=" * len(module.title) + "\n")
                write("\n")
                write(".. automodule:: " + module.name + "\n")
                write("   :show-inheritance:\n")
                write("   :members:\n")
                write("   :special-members:\n")
                write("\n")


create_new_module_documentation()


================================================
FILE: docs/test/test_sphinx_build.py
================================================
"""Test the building process of the documentation.

- All modules should be documented.
- All public methods/classes/functions/constants should be documented
"""
from test_docs import BUILD_DIRECTORY, DOCS_DIRECTORY, PYTHON_COVERAGE_FILE
import subprocess
import re
import shutil
from pytest import fixture
import os


UNDOCUMENTED_PYTHON_OBJECTS = """Undocumented Python objects
===========================
"""
WARNING_PATTERN = b"(?:checking consistency\\.\\.\\. )?" \
                  b"(.*(?:WARNING|SEVERE|ERROR):.*)"


def print_bytes(bytes_):
    """Print bytes safely as string."""
    try:
        print(bytes_.decode())
    except UnicodeDecodeError:
        print(bytes_)


@fixture(scope="module")
def sphinx_build():
    """Build the documentation with sphinx and return the output."""
    if os.path.exists(BUILD_DIRECTORY):
        shutil.rmtree(BUILD_DIRECTORY)
    output = subprocess.check_output(
            "make html", shell=True, cwd=DOCS_DIRECTORY,
            stderr=subprocess.STDOUT
        )
    output += subprocess.check_output(
            "make coverage", shell=True, cwd=DOCS_DIRECTORY,
            stderr=subprocess.STDOUT
        )
    print(output.decode())
    return output


@fixture(scope="module")
def coverage(sphinx_build):
    """:return: the documentation coverage outpupt."""
    assert sphinx_build, "we built before we try to access the result"
    with open(PYTHON_COVERAGE_FILE) as file:
        return file.read()


@fixture
def warnings(sphinx_build):
    """:return: the warnings during the build process."""
    return re.findall(WARNING_PATTERN, sphinx_build)


def test_all_methods_are_documented(coverage):
    """Make sure that everything that is public is also documented."""
    print(coverage)
    assert coverage == UNDOCUMENTED_PYTHON_OBJECTS


def test_doc_build_passes_without_warnings(warnings):
    """Make sure that the documentation is semantically correct."""
    #  WARNING: document isn't included in any toctree
    for warning in warnings:
        print_bytes(warning.strip())
    assert warnings == []


================================================
FILE: knittingpattern/Dumper/FileWrapper.py
================================================
"""This module provides wrappers for file-like objects
for encoding and decoding.

"""


class BytesWrapper(object):
    """Use this class if you have a text-file but you want to
    write bytes to it.
    """

    def __init__(self, text_file, encoding):
        """Create a wrapper around :paramref:`text_file` that decodes
        bytes to string using :paramref:`encoding` and writes them
        to :paramref:`text_file`.

        :param str encoding: The encoding to use to transfer the written bytes
          to string so they can be written to :paramref:`text_file`
        :param text_file: a file-like object open in text mode
        """
        self._file = text_file
        self._encoding = encoding

    def write(self, bytes_):
        """Write bytes to the file."""
        string = bytes_.decode(self._encoding)
        self._file.write(string)


class TextWrapper(object):
    """Use this class if you have a binary-file but you want to
    write strings to it.
    """

    def __init__(self, binary_file, encoding):
        """Create a wrapper around :paramref:`binary_file` that encodes
        strings to bytes using :paramref:`encoding` and writes them
        to :paramref:`binary_file`.

        :param str encoding: The encoding to use to transfer the written string
          to bytes so they can be written to :paramref:`binary_file`
        :param binary_file: a file-like object open in binary mode
        """
        self._file = binary_file
        self._encoding = encoding

    def write(self, string):
        """Write a string to the file."""
        bytes_ = string.encode(self._encoding)
        self._file.write(bytes_)


__all__ = ["TextWrapper", "BytesWrapper"]


================================================
FILE: knittingpattern/Dumper/__init__.py
================================================
"""Writing objects to files

This module offers a unified interface to serialize objects to strings
and save them to files.
"""
from .file import ContentDumper as ContentDumper
from .json import JSONDumper as JSONDumper
from .xml import XMLDumper as XMLDumper
from .svg import SVGDumper as SVGDumper

__all__ = ["ContentDumper", "JSONDumper", "XMLDumper", "SVGDumper"]


================================================
FILE: knittingpattern/Dumper/file.py
================================================
"""Save strings to files."""
from io import StringIO, BytesIO
from tempfile import NamedTemporaryFile
from .FileWrapper import BytesWrapper, TextWrapper


class ContentDumper(object):

    """This class is a unified interface for saving objects.

    The idea is to decouple the place to save to from the process used
    to dump the content.
    We are saving several objects such as patterns and SVGs.
    They should all have the same convenient interface.

    The process of saving something usually requires writing to some file.
    However, users may want to have the result as a string, an open file,
    a file on the hard drive on a fixed or temporary location,
    posted to some url or in a zip file.
    This class should provide for all those needs while providing a uniform
    interface for the dumping.
    """

    def __init__(self, on_dump, text_is_expected=True, encoding="UTF-8"):
        """Create a new dumper object with a function :paramref:`on_dump`

        :param on_dump: a function that takes a file-like object as argument
          and writes content to it.
        :param bool text_is_expected: whether to use text mode
          (:obj:`True`, default) or binary mode (:obj:`False`)
          for :paramref:`on_dump`.

        The dumper calls :paramref:`on_dump` with a file-like object every time
        one of its save methods, e.g. :meth:`string` or :meth:`file` is called.
        The file-like object in the :paramref:`file` argument supports the
        method ``write()`` to which the content should be written.

        :paramref:`text_is_expected` should be

        - :obj:`True` to pass a file to :paramref:`on_dump` that you can write
          strings to

        - :obj:`False` to pass a file to :paramref:`on_dump` that you can write
          bytes to
        """
        self.__dump_to_file = on_dump
        self.__text_is_expected = text_is_expected
        self.__encoding = encoding

    @property
    def encoding(self):
        """:return: the encoding for byte to string conversion
        :rtype: str"""
        return self.__encoding

    def string(self):
        """:return: the dump as a string"""
        if self.__text_is_expected:
            return self._string()
        else:
            return self._bytes().decode(self.__encoding)

    def _string(self):
        """:return: the string from a :class:`io.StringIO`"""
        file = StringIO()
        self.__dump_to_file(file)
        file.seek(0)
        return file.read()

    def bytes(self):
        """:return: the dump as bytes."""
        if self.__text_is_expected:
            return self.string().encode(self.__encoding)
        else:
            return self._bytes()

    def _bytes(self):
        """:return: bytes from a :class:`io.BytesIO`"""
        file = BytesIO()
        self.__dump_to_file(file)
        file.seek(0)
        return file.read()

    def file(self, file=None):
        """Saves the dump in a file-like object in text mode.

        :param file: :obj:`None` or a file-like object.
        :return: a file-like object

        If :paramref:`file` is :obj:`None`, a new :class:`io.StringIO`
        is returned.
        If :paramref:`file` is not :obj:`None` it should be a file-like object.

        The content is written to the file. After writing, the file's
        read/write position points behind the dumped content.
        """
        if file is None:
            file = StringIO()
        self._file(file)
        return file

    def _file(self, file):
        """Dump the content to a `file`.
        """
        if not self.__text_is_expected:
            file = BytesWrapper(file, self.__encoding)
        self.__dump_to_file(file)

    def binary_file(self, file=None):
        """Same as :meth:`file` but for binary content."""
        if file is None:
            file = BytesIO()
        self._binary_file(file)
        return file

    def _binary_file(self, file):
        """Dump the ocntent into the `file` in binary mode.
        """
        if self.__text_is_expected:
            file = TextWrapper(file, self.__encoding)
        self.__dump_to_file(file)

    def _mode_and_encoding_for_open(self):
        """:return: the file mode and encoding for :obj:`open`."""
        if self.__text_is_expected:
            return "w", self.__encoding
        return "wb", None

    def path(self, path):
        """Saves the dump in a file named :paramref:`path`.

        :param str path: a valid path to a file location. The file can exist.
        """
        self._path(path)

    def _path(self, path):
        """Saves the dump in a file named `path`."""
        mode, encoding = self._mode_and_encoding_for_open()
        with open(path, mode, encoding=encoding) as file:
            self.__dump_to_file(file)

    def _temporary_file(self, delete):
        """:return: a temporary file where the content is dumped to."""
        file = NamedTemporaryFile("w+", delete=delete,
                                  encoding=self.__encoding)
        self._file(file)
        return file

    def temporary_path(self, extension=""):
        """Saves the dump in a temporary file and returns its path.

        .. warning:: The user of this method is responsible for deleting this
                     file to save space on the hard drive.
                     If you only need a file object for a short period of time
                     you can use the method :meth:`temporary_file`.

        :param str extension: the ending ot the file name e.g. ``".png"``
        :return: a path to the temporary file
        :rtype: str
        """
        path = NamedTemporaryFile(delete=False, suffix=extension).name
        self.path(path)
        return path

    def temporary_file(self, delete_when_closed=True):
        """Saves the dump in a temporary file and returns the open file object.

        :param bool delete_when_closed: whether to delete the temporary file
                                        when it is closed.
        :return: a file-like object

        If :paramref:`delete_when_closed` is :obj:`True` (default) the file
        on the hard drive will be deleted if it is closed or not referenced
        any more.

        If :paramref:`delete_when_closed` is :obj:`False` the returned
        temporary file is not deleted when closed or unreferenced.
        The user of this method has then the responsibility to free the
        space on the host system.

        The returned file-like object has an attribute ``name`` that holds
        the location of the file.
        """
        return self._temporary_file(delete_when_closed)

    def binary_temporary_file(self, delete_when_closed=True):
        """Same as :meth:`temporary_file` but for binary mode."""
        return self._binary_temporary_file(delete_when_closed)
    temporary_binary_file = binary_temporary_file

    def _binary_temporary_file(self, delete):
        """:return: a binary temporary file where the content is dumped to."""
        file = NamedTemporaryFile("wb+", delete=delete)
        self._binary_file(file)
        return file

    def __repr__(self):
        """the string representation for people to read

        :return: the string representation of this object
        :rtype: str
        """
        return "<{} in with encoding {} >".format(
            self.__class__.__name__,
            self.__encoding
        )


__all__ = ["ContentDumper"]


================================================
FILE: knittingpattern/Dumper/json.py
================================================
"""Dump objects to JSON."""
import json
from .file import ContentDumper


class JSONDumper(ContentDumper):

    """This class can be used to dump object s as JSON."""

    def __init__(self, on_dump):
        """Create a new JSONDumper object with the callable `on_dump`.

        `on_dump` takes no arguments and returns the object that should be
        serialized to JSON."""
        super().__init__(self._dump_to_file)
        self.__dump_object = on_dump

    def object(self):
        """Return the object that should be dumped."""
        return self.__dump_object()

    def _dump_to_file(self, file):
        """dump to the file"""
        json.dump(self.object(), file)

    def knitting_pattern(self, specification=None):
        """loads a :class:`knitting pattern
        <knittingpattern.KnittingPattern.KnittingPattern>` from the dumped
        content

        :param specification: a
          :class:`~knittingpattern.ParsingSpecification.ParsingSpecification`
          or :obj:`None` to use the default specification"""
        from ..ParsingSpecification import new_knitting_pattern_set_loader
        if specification is None:
            loader = new_knitting_pattern_set_loader()
        else:
            loader = new_knitting_pattern_set_loader(specification)
        return loader.object(self.object())

__all__ = ["JSONDumper"]


================================================
FILE: knittingpattern/Dumper/svg.py
================================================
"""Dump objects to SVG."""
from .xml import XMLDumper
from os import remove as remove_file


class SVGDumper(XMLDumper):

    """This class dumps objects to SVG."""

    def kivy_svg(self):
        """An SVG object.

        :return: an SVG object
        :rtype: kivy.graphics.svg.Svg
        :raises ImportError: if the module was not found
        """
        from kivy.graphics.svg import Svg
        path = self.temporary_path(".svg")
        try:
            return Svg(path)
        finally:
            remove_file(path)

__all__ = ["SVGDumper"]


================================================
FILE: knittingpattern/Dumper/xml.py
================================================
"""Dump objects to XML."""
import xmltodict
from .file import ContentDumper


class XMLDumper(ContentDumper):

    """Used to dump objects as XML."""

    def __init__(self, on_dump):
        """Create a new XMLDumper object with the callable `on_dump`.

        `on_dump` takes no aguments and returns the object that should be
        serialized to XML."""
        super().__init__(self._dump_to_file)
        self.__dump_object = on_dump

    def object(self):
        """Return the object that should be dumped."""
        return self.__dump_object()

    def _dump_to_file(self, file):
        """dump to the file"""
        xmltodict.unparse(self.object(), file, pretty=True)

__all__ = ["XMLDumper"]


================================================
FILE: knittingpattern/IdCollection.py
================================================
"""See this module if you like to store object s that have an ``id`` attribute.
"""
from collections import OrderedDict


class IdCollection(object):
    """This is a collections of object that have an ``id`` attribute."""

    def __init__(self):
        """Create a new :class:`IdCollection` with no arguments.

        You can add objects later using the method :meth:`append`.
        """
        self._items = OrderedDict()

    def append(self, item):
        """Add an object to the end of the :class:`IdCollection`.

        :param item: an object that has an id
        """
        self._items[item.id] = item

    def at(self, index):
        """Get the object at an :paramref:`index`.

        :param int index: the index of the object
        :return: the object at :paramref:`index`
        """
        keys = list(self._items.keys())
        key = keys[index]
        return self[key]

    def __getitem__(self, id_):
        """Get the object with the :paramref:`id`

        .. code:: python

            ic = IdCollection()
            ic.append(object_1)
            ic.append(object_2)
            assert ic[object_1.id] == object_1
            assert ic[object_2.id] == object_1

        :param id_: the id of an object
        :return: the object with the :paramref:`id`
        :raises KeyError: if no object with :paramref:`id` was found
        """
        return self._items[id_]

    def __bool__(self):
        """:return: whether there is anything in the collection.
        :rtype: bool
        """
        return bool(self._items)

    def __iter__(self):
        """allows you to iterate and use for-loops

        The objects in the iterator have the order in which they were appended.
        """
        for id_ in self._items:
            yield self[id_]

    def __len__(self):
        """:return: the number of objects in this collection"""
        return len(self._items)

    @property
    def first(self):
        """The first element in this collection.

        :return: the first element in this collection
        :raises IndexError: if this collection is empty
        """
        return self.at(0)


================================================
FILE: knittingpattern/Instruction.py
================================================
"""Knitting patterns consist of instructions.

The :class:`instructions <Instruction>`. that are used in the
:class:`knitting patterns <KnittingPattern>` can be foudn in this module.
They have certain attributes in common.

"""
from .Prototype import Prototype
from .Mesh import ProducedMesh, ConsumedMesh
from .convert.color import convert_color_to_rrggbb


# pattern specification

ID = "id"  #: the id key in the specification

TYPE = "type"  #: the type key in the specification

KNIT_TYPE = "knit"  #: the type of the knit instruction

PURL_TYPE = "purl"  #: the type of the purl instruction

#: the type of the instruction without a specified type
DEFAULT_TYPE = KNIT_TYPE

COLOR = "color"  #: the color key in the specification

DESCRIPTION = "description"  #: the description in the specification

#: the key for the number of meshes that a instruction consumes
NUMBER_OF_CONSUMED_MESHES = "number of consumed meshes"

#: the default number of meshes that a instruction consumes
DEFAULT_NUMBER_OF_CONSUMED_MESHES = 1

#: the key for the number of meshes that a instruction produces
NUMBER_OF_PRODUCED_MESHES = "number of produced meshes"

#: the default number of meshes that a instruction produces
DEFAULT_NUMBER_OF_PRODUCED_MESHES = 1

#: The default z-index, see :func:`get_z`.
DEFAULT_Z = 0

#: Instructions have a default specification. In this specification the key
#: in :data:`RENDER` points to configuration for rendering.
RENDER = "render"

#: The key to look for the z-index inside the :data:`render` specification.
#: .. seealso:: :func:`get_z`, :data:`DEFAULT_Z`
RENDER_Z = "z"

# error messages

INSTRUCTION_NOT_FOUND_MESSAGE = \
    "Instruction {instruction} was not found in row {row}."


class Instruction(Prototype):

    """Instructions specify what should be done during knitting.

    This class represents the basic interface for instructions.

    It is based on the
    :class:`Prototype <knittingpattern.Prototype.Prototype>`
    which allows creating instructions based on other instructions so
    they can inherit their attributes.

    You can create new instructions by passing a specification to them which
    can consist of a :class:`dictionary <dict>` or an other
    :class:`prototype <knittingpattern.Prototype.Prototype>`.
    For such specifications see the
    :mod:`InstructionLibrary <knittingpattern.InstructionLibrary>`.
    """

    @property
    def id(self):
        """The id of the instruction.

        :return: the :data:`id <ID>` of the instruction or
          :obj:`None` if none is specified.
        """
        return self.get(ID)

    @property
    def type(self):
        """The type of the instruction.

        :return: the :data:`type <TYPE>` of the instruction or
          :data:`DEFAULT_TYPE` if none is specified.
        :rtype: str

        The type should be a string.
        Depending on the type, the instruction can receive additional
        attributes.

        .. seealso:: :mod:`knittingpattern.InstructionLibrary`
        """
        return self.get(TYPE, DEFAULT_TYPE)

    @property
    def color(self):
        """The color of the instruction.

        :return: the :data:`color <COLOR>` of the instruction or
          :obj:`None` if none is specified.
        """
        return self.get(COLOR)

    @property
    def colors(self):
        """All the colors that an instruction has.

        :return: a list of colors of the instruction. If the instruction has
          no color, this is ``[None]``.
        :rtype: list
        """
        return [self.color]

    @property
    def description(self):
        """The description of the instruction.

        :return: the :data:`description <DESCRIPTION>` of the instruction or
          :obj:`None` if none is specified.
        """
        return self.get(DESCRIPTION)

    @property
    def number_of_consumed_meshes(self):
        """The number of meshes that this instruction consumes.

        :return: the :data:`number of consumed meshes
          <NUMBER_OF_CONSUMED_MESHES>` of the instruction or
          :data:`DEFAULT_NUMBER_OF_CONSUMED_MESHES` if none is specified.
        """
        return self.get(NUMBER_OF_CONSUMED_MESHES,
                        DEFAULT_NUMBER_OF_CONSUMED_MESHES)

    @property
    def number_of_produced_meshes(self):
        """The number of meshes that this instruction produces.

        :return: the :data:`number of produced meshes
          <NUMBER_OF_PRODUCED_MESHES>` of the instruction or
          :data:`DEFAULT_NUMBER_OF_PRODUCED_MESHES` if none is specified.
        """
        return self.get(NUMBER_OF_PRODUCED_MESHES,
                        DEFAULT_NUMBER_OF_PRODUCED_MESHES)

    def has_color(self):
        """Whether this instruction has a color.

        :return: whether a :data:`color <COLOR>` is specified
        :rtype: bool
        """
        return self.color is not None

    def does_knit(self):
        """Whether this instruction is a knit instruction.

        :return: whether this instruction is a knit instruction
        :rtype: bool
        """
        return self.type == KNIT_TYPE

    def does_purl(self):
        """Whether this instruction is a purl instruction.

        :return: whether this instruction is a purl instruction
        :rtype: bool
        """
        return self.type == PURL_TYPE

    def produces_meshes(self):
        """Whether this institution produces meshes.

        :return: whether this instruction produces any meshes
        :rtype: bool

        .. seealso:: :attr:`number_of_produced_meshes`
        """
        return self.number_of_produced_meshes != 0

    def consumes_meshes(self):
        """Whether this instruction consumes meshes.

        :return: whether this instruction consumes any meshes
        :rtype: bool

        .. seealso:: :attr:`number_of_consumed_meshes`
        """
        return self.number_of_consumed_meshes != 0

    @property
    def render_z(self):
        """The z-index of the instruction when rendered.

        :return: the z-index of the instruction. Instructions with a higher
          z-index are displayed in front of instructions with lower z-index.
        :rtype: float
        """
        return self.get(RENDER, {}).get(RENDER_Z, DEFAULT_Z)

    @property
    def hex_color(self):
        """The color in "#RRGGBB" format.

        :return: the :attr:`color` in "#RRGGBB" format or none if no color is
          given
        """
        if self.has_color():
            return convert_color_to_rrggbb(self.color)
        return None

    def to_svg(self, converter=None):
        """Return a SVGDumper for this instruction.

        :param converter: a :class:`
          knittingpattern.convert.InstructionSVGCache.InstructionSVGCache` or
          :obj:`None`. If :obj:`None` is given, the :func:`
          knittingpattern.convert.InstructionSVGCache.default_svg_cache` is
          used.
        :rtype: knittingpattern.Dumper.SVGDumper
        """
        if converter is None:
            from knittingpattern.convert.InstructionSVGCache import \
                default_svg_cache
            converter = default_svg_cache()
        return converter.to_svg(self)


class InstructionInRow(Instruction):

    """Instructions can be placed in rows.

    Then, they have additional attributes and properties.
    """

    def __init__(self, row, spec):
        """Create a new instruction in a row with a specification.

        :param knittingpattern.Row.Row row: the row the instruction is placed
          in
        :param spec: specification of the instruction
        """
        super().__init__(spec)
        self._row = row
        self._produced_meshes = [
            self._new_produced_mesh(self, index)
            for index in range(self.number_of_produced_meshes)
        ]
        self._consumed_meshes = [
            self._new_consumed_mesh(self, index)
            for index in range(self.number_of_consumed_meshes)
        ]
        self._cached_index_in_row = None

    def transfer_to_row(self, new_row):
        """Transfer this instruction to a new row.

        :param knittingpattern.Row.Row new_row: the new row the instruction is
          in.
        """
        if new_row != self._row:
            index = self.get_index_in_row()
            if index is not None:
                self._row.instructions.pop(index)
            self._row = new_row

    @property
    def _new_produced_mesh(self):
        """:return: the class of the produced meshes."""
        return ProducedMesh

    @property
    def _new_consumed_mesh(self):
        """:return: the class of the consumed meshes."""
        return ConsumedMesh

    @property
    def row(self):
        """The row this instruction is in.

        :return: the row the instruction is placed in
        :rtype: knittingpattern.Row.Row
        """
        return self._row

    def is_in_row(self):
        """Whether the instruction can be found in its row.

        :return: whether the instruction is in its row
        :rtype: bool

        Use this to avoid raising and :class:`InstructionNotFoundInRow`.
        """
        return self.get_index_in_row() is not None

    def get_index_in_row(self):
        """Index of the instruction in the instructions of the row or None.

        :return: index in the :attr:`row`'s instructions or None, if the
          instruction is not in the row
        :rtype: int

        .. seealso:: :attr:`row_instructions`, :attr:`index_in_row`,
          :meth:`is_in_row`
        """
        expected_index = self._cached_index_in_row
        instructions = self._row.instructions
        if expected_index is not None and \
                0 <= expected_index < len(instructions) and \
                instructions[expected_index] is self:
            return expected_index
        for index, instruction_in_row in enumerate(instructions):
            if instruction_in_row is self:
                self._cached_index_in_row = index
                return index
        return None

    @property
    def index_in_row(self):
        """Index of the instruction in the instructions of the row.

        :return: index in the :attr:`row`'s instructions
        :rtype: int
        :raises knittingpattern.Instruction.InstructionNotFoundInRow:
          if the instruction is not found at the index

        .. code:: python

            index = instruction.index_in_row
            assert instruction.row.instructions[index] == instruction

        .. seealso:: :attr:`row_instructions`, :meth:`get_index_in_row`,
          :meth:`is_in_row`
        """
        index = self.get_index_in_row()
        if index is None:
            self._raise_not_found_error()
        return index

    @property
    def row_instructions(self):
        """Shortcut for ``instruction.row.instructions``.

        :return: the instructions of the :attr:`row` the instruction is in

        .. seealso:: :attr:`index_in_row`
        """
        return self.row.instructions

    @property
    def next_instruction_in_row(self):
        """The instruction after this one or None.

        :return: the instruction in :attr:`row_instructions` after this or
          :obj:`None` if this is the last
        :rtype: knittingpattern.Instruction.InstructionInRow

        This can be used to traverse the instructions.

        .. seealso:: :attr:`previous_instruction_in_row`
        """
        index = self.index_in_row + 1
        if index >= len(self.row_instructions):
            return None
        return self.row_instructions[index]

    @property
    def previous_instruction_in_row(self):
        """The instruction before this one or None.

        :return: the instruction in :attr:`row_instructions` before this or
          :obj:`None` if this is the first
        :rtype: knittingpattern.Instruction.InstructionInRow

        This can be used to traverse the instructions.

        .. seealso:: :attr:`next_instruction_in_row`
        """
        index = self.index_in_row - 1
        if index < 0:
            return None
        return self.row_instructions[index]

    @property
    def _instruction_not_found_message(self):
        """The message for the error.

        :return: an error message
        :rtype: str

        .. warning: private, do not use
        """
        return INSTRUCTION_NOT_FOUND_MESSAGE.format(
            instruction=self, row=self.row
        )

    def _raise_not_found_error(self):
        """Raise an error that this instruction is in its row no longer.

        :raises knittingpattern.Instruction.InstructionNotFoundInRow:
          the instruction was not found

        .. warning: private, do not use
        """
        raise InstructionNotFoundInRow(self._instruction_not_found_message)

    @property
    def index_of_first_produced_mesh_in_row(self):
        """Index of the first produced mesh in the row that consumes it.

        :return: an index of the first produced mesh of rows produced meshes
        :rtype: int

        .. note:: If the instruction :meth:`produces meshes
          <Instruction.produces_meshes>`, this is the index of the first
          mesh the instruction produces in all the meshes of the row.
          If the instruction does not produce meshes, the index of the mesh is
          returned as if the instruction had produced a mesh.

        .. code::

            if instruction.produces_meshes():
                index = instruction.index_of_first_produced_mesh_in_row

        """
        index = 0
        for instruction in self.row_instructions:
            if instruction is self:
                break
            index += instruction.number_of_produced_meshes
        else:
            self._raise_not_found_error()
        return index

    @property
    def index_of_last_produced_mesh_in_row(self):
        """Index of the last mesh produced by this instruction in its row.

        :return: an index of the last produced mesh of rows produced meshes
        :rtype: int

        .. note:: If this instruction :meth:`produces meshes
          <Instruction.produces_meshes>`, this is the index of
          its last produces mesh in the row. However, if this instruction does
          not produce meshes, this is the index **before** the first mesh of
          the instruction if it produced meshes.

        .. seealso:: :attr:`index_of_first_produced_mesh_in_row`
        """
        index = self.index_of_first_produced_mesh_in_row
        return index + self.number_of_produced_meshes - 1

    @property
    def index_of_first_consumed_mesh_in_row(self):
        """The index of the first consumed mesh of this instruction in its row.

        Same as :attr:`index_of_first_produced_mesh_in_row`
        but for consumed meshes.
        """
        index = 0
        for instruction in self.row_instructions:
            if instruction is self:
                break
            index += instruction.number_of_consumed_meshes
        else:
            self._raise_not_found_error()
        return index

    @property
    def index_of_last_consumed_mesh_in_row(self):
        """The index of the last consumed mesh of this instruction in its row.

        Same as :attr:`index_of_last_produced_mesh_in_row`
        but for the last consumed mesh.
        """
        index = self.index_of_first_consumed_mesh_in_row
        return index + self.number_of_consumed_meshes - 1

    @property
    def produced_meshes(self):
        """The meshes produced by this instruction

        :return: a :class:`list` of :class:`meshes
          <knittingpattern.Mesh.Mesh>` that this instruction produces
        :rtype: list

        .. code:: python

            assert len(inst.produced_meshes) == inst.number_of_produced_meshes
            assert all(mesh.is_produced() for mesh in inst.produced_meshes)

        .. seealso:: :attr:`consumed_meshes`, :attr:`consuming_instructions`
        """
        return self._produced_meshes

    @property
    def consumed_meshes(self):
        """The meshes consumed by this instruction

        :return: a :class:`list` of :class:`meshes
          <knittingpattern.Mesh.Mesh>` that this instruction consumes
        :rtype: list

        .. code:: python

            assert len(inst.consumed_meshes) == inst.number_of_consumed_meshes
            assert all(mesh.is_consumed() for mesh in inst.consumed_meshes)

        .. seealso:: :attr:`produced_meshes`, :attr:`producing_instructions`
        """
        return self._consumed_meshes

    def __repr__(self):
        """:obj:`repr(instruction) <repr>` used for :func:`print`.

        :return: the string representation of this object
        :rtype: str
        """
        index = self.get_index_in_row()
        if index is None:
            position = "not in {}".format(self.row)
        else:
            position = "in {} at {}".format(self.row, index)
        return "<{} {}\"{}\" {}>".format(
            self.__class__.__name__,
            ("{} ".format(self.id) if self.id is not None else ""),
            self.type,
            position
        )

    @property
    def producing_instructions(self):
        """Instructions that produce the meshes that this instruction consumes.

        :return: a list of :class:`instructions
          <knittingpattern.Instruction.InstructionInRow>`
        :rtype: list

        .. seealso:: :attr:`consuming_instructions`, :attr:`consumed_meshes`
        """
        return [(mesh.producing_instruction if mesh.is_produced() else None)
                for mesh in self.consumed_meshes]

    @property
    def consuming_instructions(self):
        """Instructions that consume the meshes that this instruction produces.

        :return: a list of :class:`instructions
          <knittingpattern.Instruction.InstructionInRow>`
        :rtype: list

        .. seealso:: :attr:`producing_instructions`, :attr:`produced_meshes`
        """
        return [(mesh.consuming_instruction if mesh.is_consumed() else None)
                for mesh in self.produced_meshes]

    @property
    def color(self):
        """The color of the instruction.

        :return: the :data:`color <COLOR>` of the instruction or
          :obj:`None` if none is specified.

        If no color is specified in the instruction, it is inherited form the
        row.
        """
        return self.get(COLOR, self.row.color)

    @property
    def last_produced_mesh(self):
        """The last produced mesh.

        :return: the last produced mesh
        :rtype: knittingpattern.Mesh.Mesh
        :raises IndexError: if no mesh is produced

        .. seealso:: :attr:`Instruction.number_of_produced_meshes`
        """
        return self._produced_meshes[-1]

    @property
    def last_consumed_mesh(self):
        """The last consumed mesh.

        :return: the last consumed mesh
        :rtype: knittingpattern.Mesh.Mesh
        :raises IndexError: if no mesh is consumed

        .. seealso:: :attr:`Instruction.number_of_consumed_meshes`
        """
        return self._consumed_meshes[-1]

    @property
    def first_produced_mesh(self):
        """The first produced mesh.

        :return: the first produced mesh
        :rtype: knittingpattern.Mesh.Mesh
        :raises IndexError: if no mesh is produced

        .. seealso:: :attr:`Instruction.number_of_produced_meshes`
        """
        return self._produced_meshes[0]

    @property
    def first_consumed_mesh(self):
        """The first consumed mesh.

        :return: the first consumed mesh
        :rtype: knittingpattern.Mesh.Mesh
        :raises IndexError: if no mesh is consumed

        .. seealso:: :attr:`Instruction.number_of_consumed_meshes`
        """
        return self._consumed_meshes[0]


class InstructionNotFoundInRow(ValueError):
    """This exception is raised if an instruction was not found in its row."""
    pass


__all__ = ["Instruction", "InstructionInRow", "InstructionNotFoundInRow",
           "ID", "TYPE", "KNIT_TYPE", "PURL_TYPE", "DEFAULT_TYPE", "COLOR",
           "NUMBER_OF_CONSUMED_MESHES", "DEFAULT_NUMBER_OF_CONSUMED_MESHES",
           "NUMBER_OF_PRODUCED_MESHES", "DEFAULT_NUMBER_OF_PRODUCED_MESHES",
           "RENDER_Z", "RENDER", "DEFAULT_Z"]


================================================
FILE: knittingpattern/InstructionLibrary.py
================================================
"""Instructions have  many attributes that do not need to be specified
in each :class:`knitting pattern set
<knittingpattern.KnittingpatternSet.KnittingpatternSet>`.

This module provides the functionality to load default values for instructions
from various locations.
"""
from .Instruction import TYPE
from .Loader import JSONLoader
from .Instruction import Instruction


class InstructionLibrary(object):
    """This library can be used to look up default specification of
    instructions.

    The specification is searched for by the type of the instruction.
    """

    @property
    def _loader_class(self):
        """:return: the class for loading the specifications with
          :attr:`load`
        """
        return JSONLoader

    @property
    def _instruction_class(self):
        """:return: the class for the specifications
        """
        return Instruction

    def __init__(self):
        """Create a new :class:`InstructionLibrary
        <knittingpattern.InstructionLibrary.InstructionLibrary>` without
        arguments.

        Use :attr:`load` to load specifications.
        """
        self._type_to_instruction = {}

    @property
    def load(self):
        """:return: a loader that can be used to load specifications
        :rtype: knittingpattern.Loader.JSONLoader

        A file to load is a list of instructions in JSON format.

        .. code:: json

            [
                {
                    "type" : "knit",
                    "another" : "attribute"
                },
                {
                    "type" : "purl"
                }
            ]

        """
        return self._loader_class(self._process_loaded_object)

    def _process_loaded_object(self, obj):
        """add the loaded instructions from :attr:`load`
        """
        for instruction in obj:
            self.add_instruction(instruction)
        return self

    def add_instruction(self, specification):
        """Add an instruction specification

        :param specification: a specification with a key
          :data:`knittingpattern.Instruction.TYPE`

        .. seealso:: :meth:`as_instruction`
        """
        instruction = self.as_instruction(specification)
        self._type_to_instruction[instruction.type] = instruction

    def as_instruction(self, specification):
        """Convert the specification into an instruction

        :param specification: a specification with a key
          :data:`knittingpattern.Instruction.TYPE`

        The instruction is not added.

        .. seealso:: :meth:`add_instruction`
        """
        instruction = self._instruction_class(specification)
        type_ = instruction.type
        if type_ in self._type_to_instruction:
            instruction.inherit_from(self._type_to_instruction[type_])
        return instruction

    def __getitem__(self, instruction_type):
        """:return: the specification for :paramref:`instruction_type`

        .. seealso:: :meth:`as_instruction`
        """
        return self.as_instruction({TYPE: instruction_type})

    @property
    def loaded_types(self):
        """The types loaded in this library.

        :return: a list of types, preferably as :class:`string <str>`
        :rtype: list
        """
        return list(self._type_to_instruction)


class DefaultInstructions(InstructionLibrary):
    """The default specifications for instructions ported with this package
    """

    #: the folder relative to this module where the instructions are located
    INSTRUCTIONS_FOLDER = "instructions"

    def __init__(self):
        """Create the default instruction library without arguments.

        The default specifications are loaded automatically form this package.
        """
        super().__init__()
        self.load.relative_folder(__file__, self.INSTRUCTIONS_FOLDER)


def default_instructions():
    """:return: a default instruction library
    :rtype: DefaultInstructions

    .. warning:: The return value is mutable and you should not add new
      instructions to it. If you would like to add instructions to it,
      create a new
      :class:`~knittingpattern.InstructionLibrary.DefaultInstructions`
      instance.
    """
    global _default_instructions
    if _default_instructions is None:
        _default_instructions = DefaultInstructions()
    return _default_instructions


_default_instructions = None
__all__ = ["InstructionLibrary", "DefaultInstructions", "default_instructions"]


================================================
FILE: knittingpattern/KnittingPattern.py
================================================
"""Here you can find the set of knit instructions in rows.

A :class:`knitting pattern set
<knittingpattern.KnittingPatternSet.KnittingPatternSet>`
consists of several :class:`KnittingPatterns
<knittingpattern.KnittingPattern.KnittingPattern>`.
Their functionality can be found in this module.
"""
from .walk import walk
from .utils import unique


class KnittingPattern(object):
    """Knitting patterns contain a set of instructions that form a pattern.

    Usually you do not create instances of this but rather load a
    :class:`knitting pattern set
    <knittingpattern.KnittingPatternSet.KnittingPatternSet>`.
    """

    def __init__(self, id_, name, rows, parser):
        """Create a new instance.

        :param id_: the id of this pattern
        :param name: the human readable name of this pattern
        :param rows: a collection of rows of instructions
        :param knittingpattern.Parser.Parser parser: the parser to use to new
          content

        .. seealso:: :func:`knittingpattern.new_knitting_pattern`
        """
        self._id = id_
        self._name = name
        self._rows = rows
        self._parser = parser

    @property
    def id(self):
        """the identifier within a :class:`set of knitting patterns
        <knittingpattern.KnittingPatternSet.KnittingPatternSet>`
        """
        return self._id

    @property
    def name(self):
        """a human readable name"""
        return self._name

    @property
    def rows(self):
        """a collection of rows that this pattern is made of

        Usually this should be a
        :class:`knittingpattern.IdCollection.IdCollection` of
        :class:`knittingpattern.Row.Row`."""
        return self._rows

    def add_row(self, id_):
        """Add a new row to the pattern.

        :param id_: the id of the row
        """
        row = self._parser.new_row(id_)
        self._rows.append(row)
        return row

    def rows_in_knit_order(self):
        """Return the rows in the order that they should be knit.

        :rtype: list
        :return: the :attr:`rows` in the order that they should be knit

        .. seealso:: :mod:`knittingpattern.walk`
        """
        return walk(self)

    @property
    def instruction_colors(self):
        """The colors of the instructions.

        :return: the colors of the instructions listed in first appearance in
          knit order
        :rtype: list
        """
        return unique([row.instruction_colors
                       for row in self.rows_in_knit_order()])

__all__ = ["KnittingPattern"]


================================================
FILE: knittingpattern/KnittingPatternSet.py
================================================
"""A set of knitting patterns that can be dumped and loaded."""

from .convert.AYABPNGDumper import AYABPNGDumper
from .Dumper import XMLDumper
from .convert.InstructionSVGCache import default_instruction_svg_cache
from .convert.Layout import GridLayout
from .convert.SVGBuilder import SVGBuilder
from .convert.KnittingPatternToSVG import KnittingPatternToSVG


class KnittingPatternSet(object):

    """This is the class for a set of knitting patterns.

    The :class:`knitting patterns
    <knittingpattern.KnittingPattern.KnittingPattern>` all have an id and can
    be accessed from here. It is possible to load this set of knitting patterns
    from various locations, see the :mod:`knittingpattern` module.
    You rarely need to create such a pattern yourself. It is easier to create
    the pattern by loading it from a file.
    """

    def __init__(self, type_, version, patterns, parser, comment=None):
        """Create a new knitting pattern set.

        This is the class for a set of :class:`knitting patterns
        <knittingpattern.KnittingPattern.KnittingPattern>`.

        :param str type: the type of the knitting pattern set, see the
          :ref:`specification <FileFormatSpecification>`.
        :param str version: the version of the knitting pattern set.
          This is not the version of the library but the version of the
          :ref:`specification <FileFormatSpecification>`.
        :param patterns: a collection of patterns. This should be a
          :class:`~knittingpattern.IdCollection.IdCollection` of
          :class:`KnittingPatterns
          <knittingpattern.KnittingPattern.KnittingPattern>`.
        :param comment: a comment about the knitting pattern
        """
        self._version = version
        self._type = type_
        self._patterns = patterns
        self._comment = comment
        self._parser = parser

    @property
    def version(self):
        """The version of the knitting pattern specification.

        :return: the version of the knitting pattern, see :meth:`__init__`
        :rtype: str

        .. seealso:: :ref:`FileFormatSpecification`
        """
        return self._version

    @property
    def type(self):
        """The type of the knitting pattern.

        :return: the type of the knitting pattern, see :meth:`__init__`
        :rtype: str

        .. seealso:: :ref:`FileFormatSpecification`
        """
        return self._type

    @property
    def patterns(self):
        """The pattern contained in this set.

        :return: the patterns of the knitting pattern, see :meth:`__init__`
        :rtype: knittingpattern.IdCollection.IdCollection

        The patterns can be accessed by their id.
        """
        return self._patterns

    @property
    def comment(self):
        """The comment about the knitting pattern.

        :return: the comment for the knitting pattern set or None,
          see :meth:`__init__`.
        """
        return self._comment

    def to_ayabpng(self):
        """Convert the knitting pattern to a png.

        :return: a dumper to save this pattern set as png for the AYAB
          software
        :rtype: knittingpattern.convert.AYABPNGDumper.AYABPNGDumper

        Example:

        .. code:: python

            >>> knitting_pattern_set.to_ayabpng().temporary_path()
            "/the/path/to/the/file.png"

        """
        return AYABPNGDumper(lambda: self)

    def to_svg(self, zoom):
        """Create an SVG from the knitting pattern set.

        :param float zoom: the height and width of a knit instruction
        :return: a dumper to save the svg to
        :rtype: knittingpattern.Dumper.XMLDumper

        Example:

        .. code:: python

            >>> knitting_pattern_set.to_svg(25).temporary_path(".svg")
            "/the/path/to/the/file.svg"
        """
        def on_dump():
            """Dump the knitting pattern to the file.

            :return: the SVG XML structure as dictionary.
            """
            knitting_pattern = self.patterns.at(0)
            layout = GridLayout(knitting_pattern)
            instruction_to_svg = default_instruction_svg_cache()
            builder = SVGBuilder()
            kp_to_svg = KnittingPatternToSVG(knitting_pattern, layout,
                                             instruction_to_svg, builder, zoom)
            return kp_to_svg.build_SVG_dict()
        return XMLDumper(on_dump)

    def add_new_pattern(self, id_, name=None):
        """Add a new, empty knitting pattern to the set.

        :param id_: the id of the pattern
        :param name: the name of the pattern to add or if :obj:`None`, the
          :paramref:`id_` is used
        :return: a new, empty knitting pattern
        :rtype: knittingpattern.KnittingPattern.KnittingPattern
        """
        if name is None:
            name = id_
        pattern = self._parser.new_pattern(id_, name)
        self._patterns.append(pattern)
        return pattern

    @property
    def first(self):
        """The first element in this set.

        :rtype: knittingpattern.KnittingPattern.KnittingPattern
        """
        return self._patterns.first


__all__ = ["KnittingPatternSet"]


================================================
FILE: knittingpattern/Loader.py
================================================
"""One can load objects from different locations.
This module provides functionality to load objects from different locations
while preserving a simple interface to the consumer.

"""
import json
import os
import sys


def identity(object_):
    """:return: the argument
    :param object_: the object to be returned"""
    return object_


def true(_):
    """:return: :obj:`True`
    :param _: can be ignored"""
    return True


class PathLoader(object):
    """Load paths and folders from the local file system.

    The :paramref:`process <PathLoader.__init__.process>` is called with a
    :class:`path <str>` as first argument: ``process(path)``.
    """

    def __init__(self, process=identity, chooses_path=true):
        """Create a PathLoader object.

        :param process: ``process(path)`` is called with the `path` to load.
          The result of :paramref:`process` is returned to the caller. The
          default value is :func:`identity`, so the paths are returned when
          loaded.
        :param chooses_path: ``chooses_path(path)`` is called before
          :paramref:`process` and returns :obj:`True` or :obj:`False`
          depending on whether a specific path should be loaded and passed to
          :paramref:`process`.
        """
        self._process = process
        self._chooses_path = chooses_path

    def folder(self, folder):
        """Load all files from a folder recursively.

        Depending on :meth:`chooses_path` some paths may not be loaded.
        Every loaded path is processed and returned part of the returned list.

        :param str folder: the folder to load the files from
        :rtype: list
        :return: a list of the results of the processing steps of the loaded
          files
        """
        result = []
        for root, _, files in os.walk(folder):
            for file in files:
                path = os.path.join(root, file)
                if self._chooses_path(path):
                    result.append(self.path(path))
        return result

    def chooses_path(self, path):
        """:return: whether the path should be loaded
        :rtype: bool

        :param str path: the path to the file to be tested
        """
        return self._chooses_path(path)

    def path(self, path):
        """load a :paramref:`path` and return the processed result

        :param str path: the path to the file to be processed
        :return: the result of processing step
        """
        return self._process(path)

    def _relative_to_absolute(self, module_location, folder):
        """:return: the absolute path for the `folder` relative to
        the module_location.
        :rtype: str
        """
        if os.path.isfile(module_location):
            path = os.path.dirname(module_location)
        elif os.path.isdir(module_location):
            path = module_location
        else:
            module_folder = os.path.dirname(module_location)
            if module_folder:
                path = module_folder
            else:
                __import__(module_location)
                module = sys.modules[module_location]
                path = os.path.dirname(module.__file__)
        absolute_path = os.path.join(path, folder)
        return absolute_path

    def relative_folder(self, module, folder):
        """Load a folder located relative to a module and return the processed
        result.

        :param str module: can be

          - a path to a folder
          - a path to a file
          - a module name

        :param str folder: the path of a folder relative to :paramref:`module`
        :return: a list of the results of the processing
        :rtype: list

        Depending on :meth:`chooses_path` some paths may not be loaded.
        Every loaded path is processed and returned part of the returned list.
        You can use :meth:`choose_paths` to find out which paths are chosen to
        load.
        """
        folder = self._relative_to_absolute(module, folder)
        return self.folder(folder)

    def relative_file(self, module, file):
        """Load a file relative to a module.

        :param str module: can be

          - a path to a folder
          - a path to a file
          - a module name

        :param str folder: the path of a folder relative to :paramref:`module`
        :return: the result of the processing

        """
        path = self._relative_to_absolute(module, file)
        return self.path(path)

    def choose_paths(self, paths):
        """:return: the paths that are chosen by :meth:`chooses_path`
        :rtype: list
        """
        return [path for path in paths if self._chooses_path(path)]

    def example(self, relative_path):
        """Load an example from the knitting pattern examples.

        :param str relative_path: the path to load
        :return: the result of the processing

        You can use :meth:`knittingpattern.Loader.PathLoader.examples`
        to find out the paths of all examples.
        """
        example_path = os.path.join("examples", relative_path)
        return self.relative_file(__file__, example_path)

    def examples(self):
        """Load all examples form the examples folder of this packge.

        :return: a list of processed examples
        :rtype: list

        Depending on :meth:`chooses_path` some paths may not be loaded.
        Every loaded path is processed and returned part of the returned list.
        """
        return self.relative_folder(__file__, "examples")


class ContentLoader(PathLoader):
    """Load contents of files and ressources.

    The :paramref:`process <PathLoader.__init__.process>` is called with a
    :class:`string <str>` as first argument: ``process(string)``.
    """

    def string(self, string):
        """:return: the processed result of a string
        :param str string: the string to load the ocntent from
        """
        return self._process(string)

    def file(self, file):
        """:return: the processed result of the content of a file-like object.

        :param file: the file-like object to load the content from.
          It should support the ``read`` method.
        """
        string = file.read()
        return self.string(string)

    def path(self, path):
        """:return: the processed result of a :paramref:`path's <path>` content.
        :param str path: the path where to load the content from.
          It should exist on the local file system.
        """
        with open(path) as file:
            return self.file(file)

    def url(self, url, encoding="UTF-8"):
        """load and process the content behind a url

        :return: the processed result of the :paramref:`url's <url>` content
        :param str url: the url to retrieve the content from
        :param str encoding: the encoding of the retrieved content.
          The default encoding is UTF-8.

        """
        import urllib.request
        with urllib.request.urlopen(url) as file:
            webpage_content = file.read()
        webpage_content = webpage_content.decode(encoding)
        return self.string(webpage_content)


class JSONLoader(ContentLoader):
    """Load an process JSON from various locations.

    The :paramref:`process <PathLoader.__init__.process>` is called with an
    :class:`object` as first argument: ``process(object)``.
    """

    def object(self, object_):
        """Processes an already loaded object.

        :return: the result of the processing step
        :param object: the object to be loaded
        """
        return self._process(object_)

    def string(self, string):
        """Load an object from a string and return the processed JSON content

        :return: the result of the processing step
        :param str string: the string to load the JSON from
        """
        object_ = json.loads(string)
        return self.object(object_)


__all__ = ["JSONLoader", "ContentLoader", "PathLoader", "true", "identity"]


================================================
FILE: knittingpattern/Mesh.py
================================================
"""This module contains the meshes of the knit work."""
from abc import ABCMeta, abstractmethod


class Mesh(metaclass=ABCMeta):

    """A mesh that is either consumed or produced by an instruction.

    .. code:: python

        assert mesh.is_produced() or mesh.is_consumed()

    Since this is an abstract base class you will only get instances of
    :class:`ProducedMesh <knittingpattern.Mesh.ProducedMesh>` and
    :class:`ConsumedMesh <knittingpattern.Mesh.ConsumedMesh>`.

    """

    @abstractmethod
    def _producing_instruction_and_index(self):
        """Replace this method."""

    @abstractmethod
    def _producing_row_and_index(self):
        """Replace this method."""

    @abstractmethod
    def _consuming_instruction_and_index(self):
        """Replace this method."""

    @abstractmethod
    def _consuming_row_and_index(self):
        """Replace this method."""

    @abstractmethod
    def _is_produced(self):
        """Replace this method."""

    @abstractmethod
    def _is_consumed(self):
        """Replace this method."""

    @abstractmethod
    def _is_consumed_mesh(self):
        """Replace this method.

        :return: whether this mesh is an instance of a ConsumedMesh.
        """

    @abstractmethod
    def _disconnect(self):
        """Replace this method."""

    @abstractmethod
    def _connect_to(self, other_mesh):
        """Replace this method."""

    @abstractmethod
    def _as_produced_mesh(self):
        """Replace this method."""

    @abstractmethod
    def _as_consumed_mesh(self):
        """Replace this method."""

    @abstractmethod
    def _is_connected_to(self, other_mesh):
        """Replace this method."""

    def _assert_is_produced(self):
        assert self._is_produced(), "Check with is_produced() before!"

    def _assert_is_consumed(self):
        assert self._is_consumed(), "Check with is_consumed() before!"

    def is_produced(self):
        """Whether the mesh has an instruction that produces it.

        :return: whether the mesh is produced by an instruction
        :rtype: bool

        If you get this mesh from
        :attr:`knittingpattern.Instruction.InstructionInRow.produced_meshes` or
        :attr:`knittingpattern.Row.Row.produced_meshes`,
        this should be :obj:`True`.

        .. warning:: Before you use any methods on how the mesh is produced,
          you should check with ``mesh.is_produced()``.
        """
        return self._is_produced()

    def is_consumed(self):
        """Whether the mesh has an instruction that consumed it.

        :return: whether the mesh is consumed by an instruction
        :rtype: bool

        If you get this mesh from
        :attr:`knittingpattern.Instruction.InstructionInRow.consumed_meshes` or
        :attr:`knittingpattern.Row.Row.consumed_meshes`,
        this should be :obj:`True`.

        .. warning:: Before you use any methods on how the mesh is consumed,
          you should check with ``mesh.is_consumed()``.
        """
        return self._is_consumed()

    @property
    def index_in_producing_instruction(self):
        """Index in instruction as a produced mesh.

        :return: the index of the mesh in the list of meshes that
          :attr:`producing_instruction` produces
        :rtype: int

        .. code:: python

            instruction = mesh.producing_instruction
            index = mesh.index_in_producing_instruction
            assert instruction.produced_meshes[index] == mesh

        .. seealso:: :attr:`producing_instruction`,
          :attr:`index_in_consuming_instruction`

        .. warning:: Check with :meth:`is_produced` before!
        """
        self._assert_is_produced()
        return self._producing_instruction_and_index()[1]

    @property
    def producing_instruction(self):
        """Instruction which produces this mesh.

        :return: the instruction that produces this mesh
        :rtype: knittingpattern.Instruction.InstructionInRow

        .. seealso:: :attr:`index_in_producing_instruction`,
          :attr:`producing_row`, :attr:`consuming_row`

        .. warning:: Check with :meth:`is_produced` before!
        """
        self._assert_is_produced()
        return self._producing_instruction_and_index()[0]

    @property
    def producing_row(self):
        """Row which produces this mesh.

        :return: the row of the instruction that produces this mesh
        :rtype: knittingpattern.Row.Row

        .. seealso:: :attr:`index_in_producing_row`,
          :attr:`producing_instruction`, :attr:`consuming_row`

        .. warning:: Check with :meth:`is_produced` before!
        """
        self._assert_is_produced()
        return self._producing_row_and_index()[0]

    @property
    def index_in_producing_row(self):
        """Index in row as produced mesh.

        :return: the index of the mesh in the :attr:`producing_row`
        :rtype: int

        .. code:: python

            row = mesh.producing_row
            index = mesh.index_in_producing_row
            assert row[index] == mesh

        .. seealso:: :attr:`producing_row`, :attr:`index_in_consuming_row`

        .. warning:: Check with :meth:`is_produced` before!
        """
        self._assert_is_produced()
        return self._producing_row_and_index()[1]

    @property
    def index_in_consuming_row(self):
        """Index in row as consumed mesh.

        :return: the index of the mesh in the list of meshes that
          :attr:`consuming_row` consumes
        :rtype: int

        .. code:: python

            row = mesh.consuming_row
            index = mesh.index_in_consuming_row
            assert row.consumed_meshes[index] == mesh

        .. seealso:: :attr:`consuming_row`, :attr:`index_in_producing_row`

        .. warning:: Check with :meth:`is_consumed` before!
        """
        self._assert_is_consumed()
        return self._consuming_row_and_index()[1]

    @property
    def consuming_row(self):
        """Row which consumes this mesh.

        :return: the row that consumes this mesh
        :rtype: knittingpattern.Row.Row

        .. seealso:: :attr:`index_in_consuming_row`,
          :attr:`consuming_instruction`, :attr:`producing_row`

        .. warning:: Check with :meth:`is_consumed` before!
        """
        self._assert_is_consumed()
        return self._consuming_row_and_index()[0]

    @property
    def consuming_instruction(self):
        """Instruction which consumes this mesh.

        :return: the instruction that consumes this mesh
        :rtype: knittingpattern.Instruction.InstructionInRow

        .. seealso:: :attr:`index_in_consuming_instruction`,
          :attr:`consuming_row`, :attr:`producing_instruction`

        .. warning:: Check with :meth:`is_consumed` before!
        """
        self._assert_is_consumed()
        return self._consuming_instruction_and_index()[0]

    @property
    def index_in_consuming_instruction(self):
        """Index in instruction as consumed mesh.

        :return: the index of the mesh in the list of meshes that
          :attr:`consuming_instruction` consumes
        :rtype: int

        .. code:: python

            instruction = mesh.consuming_instruction
            index = mesh.index_in_consuming_instruction
            assert instruction.consumed_meshes[index] == mesh

        .. seealso:: :attr:`consuming_instruction`,
          :attr:`index_in_consuming_instruction`

        .. warning:: Check with :meth:`is_consumed` before!
        """
        self._assert_is_consumed()
        return self._consuming_instruction_and_index()[1]

    def is_knit(self):
        """Whether the mesh is produced by a knit instruction.

        :return: whether the mesh is knit by an instruction
        :rtype: bool

        .. seealso:: :attr:`producing_instruction`
        """
        self._assert_is_produced()
        return self._producing_instruction_and_index()[0].does_knit()

    def __repr__(self):
        """This mesh as string.

        :return: the string representation of this mesh.
        :rtype: str

        This is useful for :func:`print` and class:`str`
        """
        if self._is_consumed():
            instruction, _ = self._consuming_instruction_and_index()
            row, row_index = self._consuming_row_and_index()
            consume_string = " for {} in {}[{}]".format(
                instruction,
                row,
                row_index
            )
        else:
            consume_string = ""
        if self._is_produced():
            instruction, _ = self._producing_instruction_and_index()
            row, row_index = self._producing_row_and_index()
            produce_string = " by {} in {}[{}]".format(
                instruction,
                row,
                row_index
            )
        else:
            produce_string = ""
        return "<{}{}{}>".format(
            self.__class__.__name__, produce_string, consume_string
        )

    def disconnect(self):
        """Remove the connection between two rows through this mesh.

        After disconnecting this mesh, it can be connected anew.
        """
        if self.is_connected():
            self._disconnect()

    def connect_to(self, other_mesh):
        """Create a connection to an other mesh.

        .. warning:: Both meshes need to be disconnected and one needs to be
          a consumed and the other a produced mesh. You can check if a
          connection is possible using :meth:`can_connect_to`.

        .. seealso:: :meth:`is_consumed`, :meth:`is_produced`,
          :meth:`can_connect_to`
        """
        other_mesh.disconnect()
        self.disconnect()
        self._connect_to(other_mesh)

    def is_connected(self):
        """Returns whether this mesh is already connected.

        :return: whether this mesh is connected to an other.
        :rtype: bool
        """
        return self._is_consumed() and self._is_produced()

    def as_produced_mesh(self):
        """The produced part to this mesh.

        If meshes are split up, it may be important which row the mesh is
        connected to afterwards. This method returns the mesh that is
        connected to the :attr:`producing row <producing_row>`.

        If you got this mesh from :attr:`InstructionInRow.produced_meshes
        <knittinpattern.Instruction.InstructionInRow.produced_meshes>` or
        :attr:`Row.produced_meshes <knittinpattern.Row.Row.produced_meshes>`,
        this returns the same object.

        .. seealso:: :meth:`as_consumed_mesh`,
          :attr:`knittinpattern.Instruction.InstructionInRow.produced_meshes`,
          :attr:`knittinpattern.Row.Row.produced_meshes`
        """
        self._assert_is_produced()
        return self._as_produced_mesh()

    def as_consumed_mesh(self):
        """The consumed part to this mesh."""
        self._assert_is_consumed()
        return self._as_consumed_mesh()

    def is_mesh(self):
        """Whether this object is a mesh.

        :return: :obj:`True`
        :rtype: bool
        """
        return True

    def is_connected_to(self, other_mesh):
        """Whether the one mesh is conencted to the other."""
        assert other_mesh.is_mesh()
        return self._is_connected_to(other_mesh)

    def can_connect_to(self, other):
        """Whether a connection can be established between those two meshes."""
        assert other.is_mesh()
        disconnected = not other.is_connected() and not self.is_connected()
        types_differ = self._is_consumed_mesh() != other._is_consumed_mesh()
        return disconnected and types_differ


class ProducedMesh(Mesh):
    """A :class:`~knittingpattern.Mesh.Mesh` that has a producing instruction
    """

    def __init__(self, producing_instruction,
                 index_in_producing_instruction):
        """
        :param producing_instruction: the
          :class:`instruction <knittingpattern.Instruction.InstructionInRow>`
          that produces the mesh
        :param int index_in_producing_instruction: the index of the mesh
          in the list of meshes that :attr:`producing_instruction`
          produces

        .. note:: There should be no necessity to create instances of this
          directly. You should be able to use
          ``instruction.produced_meshes`` or ``instruction.consumed_meshes``
          to access the :class:`meshes <knittingpattern.Mesh.Mesh>`.

        """
        self.__producing_instruction_and_index = (
            producing_instruction,
            index_in_producing_instruction
        )
        self._consumed_part = None

    def _producing_instruction_and_index(self):
        return self.__producing_instruction_and_index

    def _producing_row_and_index(self):
        instruction, index = self.__producing_instruction_and_index
        producing_row = instruction.row
        return (producing_row,
                index + instruction.index_of_first_produced_mesh_in_row)

    def _consuming_instruction_and_index(self):
        return self._consumed_part._consuming_instruction_and_index()

    def _consuming_row_and_index(self):
        return self._consumed_part._consuming_row_and_index()

    def _is_produced(self):
        return True

    def _is_consumed(self):
        return self._consumed_part is not None

    def _is_consumed_mesh(self):
        return False

    def _disconnect(self):
        assert self._consumed_part is not None, "Use is_consumed() before."
        self._consumed_part._disconnected()
        self._consumed_part = None

    def _connect_to(self, other_mesh):
        assert other_mesh._is_consumed_mesh()
        self._consumed_part = other_mesh
        self._consumed_part._connect_to_produced_mesh(self)

    def _as_produced_mesh(self):
        return self

    def _as_consumed_mesh(self):
        assert self._consumed_part is not None
        return self._consumed_part

    def _is_connected_to(self, other_mesh):
        return other_mesh is not None and other_mesh == self._consumed_part


class ConsumedMesh(Mesh):
    """A mesh that is only consumed by an instruction"""

    def __init__(self, consuming_instruction,
                 index_in_consuming_instruction):
        """
        :param consuming_instruction: the
          :class:`instruction <knittingpattern.Instruction.InstructionInRow>`
          that consumes the mesh
        :param int index_in_consuming_instruction: the index of the mesh
          in the list of meshes that :attr:`consuming_instruction`
          consumes

        .. note:: There should be no necessity to create instances of this
          directly. You should be able to use
          ``instruction.produced_meshes`` or ``instruction.consumed_meshes``
          to access the :class:`meshes <knittingpattern.Mesh.Mesh>`.

        """
        self.__consuming_instruction_and_index = (
            consuming_instruction,
            index_in_consuming_instruction
        )
        self._produced_part = None

    def _producing_instruction_and_index(self):
        return self._produced_part._producing_instruction_and_index()

    def _producing_row_and_index(self):
        return self._produced_part._producing_row_and_index()

    def _consuming_instruction_and_index(self):
        return self.__consuming_instruction_and_index

    def _consuming_row_and_index(self):
        instruction, index = self.__consuming_instruction_and_index
        consuming_row = instruction.row
        return (
            consuming_row, index +
            instruction.index_of_first_consumed_mesh_in_row)

    def _is_produced(self):
        return self._produced_part is not None

    def _is_consumed(self):
        return True

    def _is_consumed_mesh(self):
        return True

    def _disconnect(self):
        assert self._produced_part is not None
        self._produced_part._disconnect()

    def _disconnected(self):
        self._produced_part = None

    def _connect_to(self, other_mesh):
        assert not other_mesh._is_consumed_mesh()
        other_mesh._connect_to(self)

    def _connect_to_produced_mesh(self, produced_mesh):
        """This is called after a connection has been established by the
        produced mesh."""
        self._produced_part = produced_mesh

    def _as_produced_mesh(self):
        assert self._produced_part is not None
        return self._produced_part

    def _as_consumed_mesh(self):
        return self

    def _is_connected_to(self, other_mesh):
        if other_mesh._is_consumed_mesh():
            return False
        return other_mesh is not self and other_mesh._is_connected_to(self)

__all__ = ["Mesh", "ProducedMesh", "ConsumedMesh"]


================================================
FILE: knittingpattern/Parser.py
================================================
"""In this module you can find the parsing of knitting pattern structures."""
# attributes

ID = "id"  #: the id of a row, an instruction or a pattern
NAME = "name"  #: the name of a row
TYPE = "type"  #: the type of an instruction or the knitting pattern set
VERSION = "version"  #: the version of a knitting pattern set
INSTRUCTIONS = "instructions"  #: the instructions in a row
SAME_AS = "same as"  #: pointer to a inherit from
PATTERNS = "patterns"  #: the patterns in the knitting pattern set
ROWS = "rows"  #: the rows inside a pattern
CONNECTIONS = "connections"  #: the connections in a pattern
FROM = "from"  #: the position and row a connection comes from
TO = "to"  #: the position and row a connection goes to
START = "start"  #: the mesh index the connection starts at
#: the default mesh index the connection starts at if none is given
DEFAULT_START = 0
MESHES = "meshes"  #: the number of meshes of a connection
COMMENT = "comment"  #: a comment of a row, an instruction, anything

# constants

#: the default type of the knitting pattern set
KNITTING_PATTERN_TYPE = "knitting pattern"


class ParsingError(ValueError):

    """Mistake in the provided object to parse.

    This Error is raised if there is an error during the parsing for
    :class:`~knittingpattern.Parser.Parser`.
    """


class Parser(object):

    """Parses a knitting pattern set and anything in it."""

    def __init__(self, specification):
        """Create a parser with a specification.

        :param specification: the types and classes to use for the resulting
          object structure, preferably a
          :class:`knittingpattern.ParsingSpecification.ParsingSpecification`

        """
        self._spec = specification
        self._start()

    def _start(self):
        """Initialize the parsing process."""
        self._instruction_library = self._spec.new_default_instructions()
        self._as_instruction = self._instruction_library.as_instruction
        self._id_cache = {}
        self._pattern_set = None
        self._inheritance_todos = []
        self._instruction_todos = []

    @staticmethod
    def _to_id(id_):
        """Converts the argument to a object suitable as an identifier.

        :return: a hashable object
        """
        return tuple(id_) if isinstance(id_, list) else id_

    def _error(self, text):
        """Raise an error.

        :raises: a specified ParsingError
        :param str text: the text to include in the error message
        """
        raise self._spec.new_parsing_error(text)

    def knitting_pattern_set(self, values):
        """Parse a knitting pattern set.

        :param dict value: the specification of the knitting pattern set
        :rtype: knittingpattern.KnittingPatternSet.KnittingPatternSet
        :raises knittingpattern.KnittingPatternSet.ParsingError: if
          :paramref:`value` does not fulfill the :ref:`specification
          <FileFormatSpecification>`.

        """
        self._start()
        pattern_collection = self._new_pattern_collection()
        self._fill_pattern_collection(pattern_collection, values)
        self._create_pattern_set(pattern_collection, values)
        return self._pattern_set

    def _finish_inheritance(self):
        """Finish those who still need to inherit."""
        while self._inheritance_todos:
            prototype, parent_id = self._inheritance_todos.pop()
            parent = self._id_cache[parent_id]
            prototype.inherit_from(parent)

    def _delay_inheritance(self, prototype, parent_id):
        """Add a deleyed inheritance that is ti be resolved later.

        When calling :meth:`_finish_inheritance` this inheritance chain shall
        be resolved.
        """
        self._inheritance_todos.append((prototype, parent_id))

    def _finish_instructions(self):
        """Finish those who still need to inherit."""
        while self._instruction_todos:
            row = self._instruction_todos.pop()
            instructions = row.get(INSTRUCTIONS, [])
            row.instructions.extend(instructions)

    def _delay_instructions(self, row):
        """Add a deleyed inheritance that is ti be resolved later.

        When calling :meth:`_finish_instructions` this inheritance chain shall
        be resolved.
        """
        self._instruction_todos.append(row)

    def _new_pattern_collection(self):
        """Create a new pattern collection.

        :return: a new specified pattern collection for
          :meth:`knitting_pattern_set`
        """
        return self._spec.new_pattern_collection()

    def new_row_collection(self):
        """Create a new row collection.

        :return: a new specified row collection for the
          :meth:`knitting pattern <new_pattern>`
        """
        return self._spec.new_row_collection()

    def _fill_pattern_collection(self, pattern_collection, values):
        """Fill a pattern collection."""
        pattern = values.get(PATTERNS, [])
        for pattern_to_parse in pattern:
            parsed_pattern = self._pattern(pattern_to_parse)
            pattern_collection.append(parsed_pattern)

    def _row(self, values):
        """Parse a row."""
        row_id = self._to_id(values[ID])
        row = self._spec.new_row(row_id, values, self)
        if SAME_AS in values:
            self._delay_inheritance(row, self._to_id(values[SAME_AS]))
        self._delay_instructions(row)
        self._id_cache[row_id] = row
        return row

    def new_row(self, id_):
        """Create a new row with an id.

        :param id_: the id of the row
        :return: a row
        :rtype: knittingpattern.Row.Row
        """
        return self._spec.new_row(id_, {}, self)

    def instruction_in_row(self, row, specification):
        """Parse an instruction.

        :param row: the row of the instruction
        :param specification: the specification of the instruction
        :return: the instruction in the row
        """
        whole_instruction_ = self._as_instruction(specification)
        return self._spec.new_instruction_in_row(row, whole_instruction_)

    def _pattern(self, base):
        """Parse a pattern."""
        rows = self._rows(base.get(ROWS, []))
        self._finish_inheritance()
        self._finish_instructions()
        self._connect_rows(base.get(CONNECTIONS, []))
        id_ = self._to_id(base[ID])
        name = base[NAME]
        return self.new_pattern(id_, name, rows)

    def new_pattern(self, id_, name, rows=None):
        """Create a new knitting pattern.

        If rows is :obj:`None` it is replaced with the
        :meth:`new_row_collection`.
        """
        if rows is None:
            rows = self.new_row_collection()
        return self._spec.new_pattern(id_, name, rows, self)

    def _rows(self, spec):
        """Parse a collection of rows."""
        rows = self.new_row_collection()
        for row in spec:
            rows.append(self._row(row))
        return rows

    def _connect_rows(self, connections):
        """Connect the parsed rows."""
        for connection in connections:
            from_row_id = self._to_id(connection[FROM][ID])
            from_row = self._id_cache[from_row_id]
            from_row_start_index = connection[FROM].get(START, DEFAULT_START)
            from_row_number_of_possible_meshes = \
                from_row.number_of_produced_meshes - from_row_start_index
            to_row_id = self._to_id(connection[TO][ID])
            to_row = self._id_cache[to_row_id]
            to_row_start_index = connection[TO].get(START, DEFAULT_START)
            to_row_number_of_possible_meshes = \
                to_row.number_of_consumed_meshes - to_row_start_index
            meshes = min(from_row_number_of_possible_meshes,
                         to_row_number_of_possible_meshes)
            # TODO: test all kinds of connections
            number_of_meshes = connection.get(MESHES, meshes)
            from_row_stop_index = from_row_start_index + number_of_meshes
            to_row_stop_index = to_row_start_index + number_of_meshes
            assert 0 <= from_row_start_index <= from_row_stop_index
            produced_meshes = from_row.produced_meshes[
                from_row_start_index:from_row_stop_index]
            assert 0 <= to_row_start_index <= to_row_stop_index
            consumed_meshes = to_row.consumed_meshes[
                to_row_start_index:to_row_stop_index]
            assert len(produced_meshes) == len(consumed_meshes)
            mesh_pairs = zip(produced_meshes, consumed_meshes)
            for produced_mesh, consumed_mesh in mesh_pairs:
                produced_mesh.connect_to(consumed_mesh)

    def _get_type(self, values):
        """:return: the type of a knitting pattern set."""
        if TYPE not in values:
            self._error("No pattern type given but should be "
                        "\"{}\"".format(KNITTING_PATTERN_TYPE))
        type_ = values[TYPE]
        if type_ != KNITTING_PATTERN_TYPE:
            self._error("Wrong pattern type. Type is \"{}\" "
                        "but should be \"{}\""
                        "".format(type_, KNITTING_PATTERN_TYPE))
        return type_

    def _get_version(self, values):
        """:return: the version of :paramref:`values`."""
        return values[VERSION]

    def _create_pattern_set(self, pattern, values):
        """Create a new pattern set."""
        type_ = self._get_type(values)
        version = self._get_version(values)
        comment = values.get(COMMENT)
        self._pattern_set = self._spec.new_pattern_set(
            type_, version, pattern, self, comment
        )


def default_parser():
    """The parser with a default specification.

    :return: a parser using a
      :class:`knittingpattern.ParsingSpecification.DefaultSpecification`
    :rtype: knittingpattern.Parser.Parser
    """
    from .ParsingSpecification import DefaultSpecification
    specification = DefaultSpecification()
    return Parser(specification)


__all__ = ["Parser", "ID", "NAME", "TYPE", "VERSION", "INSTRUCTIONS",
           "SAME_AS", "PATTERNS", "ROWS", "CONNECTIONS", "FROM", "TO", "START",
           "DEFAULT_START", "MESHES", "COMMENT", "ParsingError",
           "default_parser"]


================================================
FILE: knittingpattern/ParsingSpecification.py
================================================
"""This modules specifies how to convert JSON to knitting patterns.

When parsing :class:`knitting patterns
<knittingpattern.KnittingPatternSet.KnittingPatternSet>` a lot of classes can
be used.

The :class:`ParsingSpecification` is the one place where to go to change a
class that is used throughout the whole structure loaded by e.g. a
:class:`knittingpattern.Parser.Parser`.
:func:`new_knitting_pattern_set_loader` is a convinient interface for
loading knitting patterns.

These functions should do the same:

.. code:: python

    # (1) load from module
    import knittingpattern
    kp = knittingpattern.load_from_file("my_pattern")

    # (2) load from knitting pattern
    from knittingpattern.ParsingSpecification import *
    kp = new_knitting_pattern_set_loader().file("my_pattern")

"""
from .Loader import JSONLoader
from .Parser import Parser, ParsingError
from .KnittingPatternSet import KnittingPatternSet
from .IdCollection import IdCollection
from .KnittingPattern import KnittingPattern
from .Row import Row
from .InstructionLibrary import DefaultInstructions
from .Instruction import InstructionInRow


class ParsingSpecification(object):

    """This is the specification for knitting pattern parsers.

    The :class:`<knittingpattern.Parser.Parser>` uses this specification
    to parse the knitting patterns. You can change every class in the data
    structure to add own functionality.
    """

    def __init__(self,
                 new_loader=JSONLoader,
                 new_parser=Parser,
                 new_parsing_error=ParsingError,
                 new_pattern_set=KnittingPatternSet,
                 new_pattern_collection=IdCollection,
                 new_row_collection=IdCollection,
                 new_pattern=KnittingPattern,
                 new_row=Row,
                 new_default_instructions=DefaultInstructions,
                 new_instruction_in_row=InstructionInRow):
        """Create a new parsing specification."""
        self.new_loader = new_loader
        self.new_parser = new_parser
        self.new_parsing_error = new_parsing_error
        self.new_pattern_set = new_pattern_set
        self.new_pattern_collection = new_pattern_collection
        self.new_row_collection = new_row_collection
        self.new_pattern = new_pattern
        self.new_row = new_row
        self.new_default_instructions = new_default_instructions
        self.new_instruction_in_row = new_instruction_in_row


class DefaultSpecification(ParsingSpecification):

    """This is the default specification.

    It is created like pasing no arguments to :class:`ParsingSpecification`.
    The idea is to make the default specification easy to spot and create.
    """

    def __init__(self):
        """Initialize the default specification with no arguments."""
        super().__init__()

    @classmethod
    def __repr__(cls):
        """The string representation of the object.

        :return: the string representation
        :rtype: str
        """
        return "<{}.{}>".format(cls.__module__, cls.__qualname__)


def new_knitting_pattern_set_loader(specification=DefaultSpecification()):
    """Create a loader for a knitting pattern set.

    :param specification: a :class:`specification
      <knittingpattern.ParsingSpecification.ParsingSpecification>`
      for the knitting pattern set, default
      :class:`DefaultSpecification`
    """
    parser = specification.new_parser(specification)
    loader = specification.new_loader(parser.knitting_pattern_set)
    return loader


__all__ = ["ParsingSpecification", "new_knitting_pattern_set_loader",
           "DefaultSpecification"]


================================================
FILE: knittingpattern/Prototype.py
================================================
"""This module contains the :class:`~knittingpattern.Prototype.Prototype`
that can be used to create inheritance on object level instead of class level.
"""


class Prototype(object):
    """This class provides inheritance of its specifications on object level.

    .. _prototype-key:

    Throughout this class `specification key` refers to a
    :func:`hashable <hash>` object
    to look up a value in the specification.
    """

    def __init__(self, specification, inherited_values=()):
        """create a new prototype

        :param specification: the specification of the prototype.
          This specification can be inherited by other prototypes.
          It can be a :class:`dict` or an other
          :class:`knittingpattern.Prototype.Prototype` or anything else that
          supports :meth:`__contains__` and :meth:`__getitem__`

        To look up a key in the specification it will be walked through

        1. :paramref:`specification`
        2. :paramref:`inherited_values` in order

        However, new lookups can be inserted at before
        :paramref:`inherited_values`, by calling :meth:`inherit_from`.

        """
        self.__specification = [specification] + list(inherited_values)

    def get(self, key, default=None):
        """
        :return: the value behind :paramref:`key` in the specification.
          If no value was found, :paramref:`default` is returned.
        :param key: a :ref:`specification key <prototype-key>`
        """
        for base in self.__specification:
            if key in base:
                return base[key]
        return default

    def __getitem__(self, key):
        """``prototype[key]``

        :param key: a :ref:`specification key <prototype-key>`
        :return: the value behind :paramref:`key` in the specification
        :raises KeyError: if no value was found

        """
        default = []
        value = self.get(key, default)
        if value is default:
            raise KeyError(key)
        return value

    def __contains__(self, key):
        """``key in prototype``

        :param key: a :ref:`specification key <prototype-key>`
        :return: whether the key was found in the specification
        :rtype: bool

        """
        default = []
        value = self.get(key, default)
        return value is not default

    def inherit_from(self, new_specification):
        """Inherit from a :paramref:`new_specification`

        :param new_specification: a specification as passed to :meth:`__init__`

        The :paramref:`new_specification` is inserted before the first
        :paramref:`inherited value <__init__.inherited_values>`.

        If the order is

        1. :paramref:`~__init__.specification`
        2. :paramref:`~__init__.inherited_values`

        after calling ``prototype.inherit_from(new_specification)`` the lookup
        order is

        1. :paramref:`~__init__.specification`
        2. :paramref:`new_specification`
        3. :paramref:`~__init__.inherited_values`

        """
        self.__specification.insert(1, new_specification)


__all__ = ["Prototype"]


================================================
FILE: knittingpattern/Row.py
================================================
"""This module contains the rows of instructions of knitting patterns.

The :class:`rows <Row>` are part of :class:`knitting patterns
<knittingpattern.KnittingPattern.KnittingPattern>`.
They contain :class:`instructions
<knittingpattern.Instruction.InstructionInRow>` and can be connected to other
rows.
"""
from .Prototype import Prototype
from itertools import chain
from ObservableList import ObservableList
from .utils import unique

COLOR = "color"  #: the color of the row

#: an error message
CONISTENCY_MESSAGE = "The data structure must be consistent."


class Row(Prototype):

    """This class contains the functionality for rows.

    This class is used by :class:`knitting patterns
    <knittingpattern.KnittingPattern.KnittingPattern>`.
    """

    def __init__(self, row_id, values, parser):
        """Create a new row.

        :param row_id: an identifier for the row
        :param values: the values from the specification
        :param list inheriting_from: a list of specifications to inherit values
          from, see :class:`knittingpattern.Prototype.Prototype`

        .. note:: Seldomly, you need to create this row on your own. You can
          load it with the :mod:`knittingpattern` or the
          :class:`knittingpattern.Parser.Parser`.
        """
        super().__init__(values)
        self._id = row_id
        self._instructions = ObservableList()
        self._instructions.register_observer(self._instructions_changed)
        self._parser = parser

    def _instructions_changed(self, change):
        """Call when there is a change in the instructions."""
        if change.adds():
            for index, instruction in change.items():
                if isinstance(instruction, dict):
                    in_row = self._parser.instruction_in_row(self, instruction)
                    self.instructions[index] = in_row
                else:
                    instruction.transfer_to_row(self)

    @property
    def id(self):
        """The id of the row.

        :return: the id of the row
        """
        return self._id

    @property
    def instructions(self):
        """The instructions in this row.

        :return: a collection of :class:`instructions inside the row
          <knittingpattern.Instruction.InstructionInRow>`
        :rtype: ObservableList.ObservableList
        """
        return self._instructions

    @property
    def number_of_produced_meshes(self):
        """The number of meshes that this row produces.

        :return: the number of meshes that this row produces
        :rtype: int

        .. seealso::
          :meth:`Instruction.number_of_produced_meshes()
          <knittingpattern.Instruction.Instruction.number_of_produced_meshes>`,
          :meth:`number_of_consumed_meshes`
        """
        return sum(instruction.number_of_produced_meshes
                   for instruction in self.instructions)

    @property
    def number_of_consumed_meshes(self):
        """The number of meshes that this row consumes.

        :return: the number of meshes that this row consumes
        :rtype: int

        .. seealso::
          :meth:`Instruction.number_of_consumed_meshes()
          <knittingpattern.Instruction.Instruction.number_of_consumed_meshes>`,
          :meth:`number_of_produced_meshes`
        """
        return sum(instruction.number_of_consumed_meshes
                   for instruction in self.instructions)

    @property
    def produced_meshes(self):
        """The meshes that this row produces with its instructions.

        :return: a collection of :class:`meshes <knittingpattern.Mesh.Mesh>`
          that this instruction produces

        """
        return list(chain(*(instruction.produced_meshes
                            for instruction in self.instructions)))

    @property
    def consumed_meshes(self):
        """Same as :attr:`produced_meshes` but for consumed meshes."""
        return list(chain(*(instruction.consumed_meshes
                            for instruction in self.instructions)))

    def __repr__(self):
        """The string representation of this row.

        :return: a string representation of this row
        :rtype: str
        """
        return "<{} {}>".format(self.__class__.__qualname__, self.id)

    @property
    def color(self):
        """The color of the row.

        :return: the color of the row as specified or :obj:`None`
        """
        return self.get(COLOR)

    @property
    def instruction_colors(self):
        """The colors of the instructions in the row in the order tehy appear.

        :return: a list of colors of the knitting pattern in the order that
          they appear in
        :rtype: list
        """
        return unique(instruction.colors for instruction in self.instructions)

    @property
    def last_produced_mesh(self):
        """The last produced mesh.

        :return: the last produced mesh
        :rtype: knittingpattern.Mesh.Mesh
        :raises IndexError: if no mesh is produced

        .. seealso:: :attr:`number_of_produced_meshes`
        """
        for instruction in reversed(self.instructions):
            if instruction.produces_meshes():
                return instruction.last_produced_mesh
        raise IndexError("{} produces no meshes".format(self))

    @property
    def last_consumed_mesh(self):
        """The last consumed mesh.

        :return: the last consumed mesh
        :rtype: knittingpattern.Mesh.Mesh
        :raises IndexError: if no mesh is consumed

        .. seealso:: :attr:`number_of_consumed_meshes`
        """
        for instruction in reversed(self.instructions):
            if instruction.consumes_meshes():
                return instruction.last_consumed_mesh
        raise IndexError("{} consumes no meshes".format(self))

    @property
    def first_produced_mesh(self):
        """The first produced mesh.

        :return: the first produced mesh
        :rtype: knittingpattern.Mesh.Mesh
        :raises IndexError: if no mesh is produced

        .. seealso:: :attr:`number_of_produced_meshes`
        """
        for instruction in self.instructions:
            if instruction.produces_meshes():
                return instruction.first_produced_mesh
        raise IndexError("{} produces no meshes".format(self))

    @property
    def first_consumed_mesh(self):
        """The first consumed mesh.

        :return: the first consumed mesh
        :rtype: knittingpattern.Mesh.Mesh
        :raises IndexError: if no mesh is consumed

        .. seealso:: :attr:`number_of_consumed_meshes`
        """
        for instruction in self.instructions:
            if instruction.consumes_meshes():
                return instruction.first_consumed_mesh
        raise IndexError("{} consumes no meshes".format(self))

    @property
    def rows_before(self):
        """The rows that produce meshes for this row.

        :rtype: list
        :return: a list of rows that produce meshes for this row. Each row
          occurs only once. They are sorted by the first occurrence in the
          instructions.
        """
        rows_before = []
        for mesh in self.consumed_meshes:
            if mesh.is_produced():
                row = mesh.producing_row
                if rows_before not in rows_before:
                    rows_before.append(row)
        return rows_before

    @property
    def rows_after(self):
        """The rows that consume meshes from this row.

        :rtype: list
        :return: a list of rows that consume meshes from this row. Each row
          occurs only once. They are sorted by the first occurrence in the
          instructions.
        """
        rows_after = []
        for mesh in self.produced_meshes:
            if mesh.is_consumed():
                row = mesh.consuming_row
                if rows_after not in rows_after:
                    rows_after.append(row)
        return rows_after

    @property
    def first_instruction(self):
        """The first instruction of the rows instructions.

        :rtype: knittingpattern.Instruction.InstructionInRow
        :return: the first instruction in this row's :attr:`instructions`
        """
        return self.instructions[0]

    @property
    def last_instruction(self):
        """The last instruction of the rows instructions.

        :rtype: knittingpattern.Instruction.InstructionInRow
        :return: the last instruction in this row's :attr:`instructions`
        """
        return self.instructions[-1]

__all__ = ["Row", "COLOR"]


================================================
FILE: knittingpattern/__init__.py
================================================
"""The knitting pattern module.

Load and convert knitting patterns using the convenience functions listed
below.
"""
# there should be no imports

#: the version of the knitting pattern library
__version__ = '0.1.19'

#: an empty knitting pattern set as specification
EMPTY_KNITTING_PATTERN_SET = {"version": "0.1", "type": "knitting pattern",
                              "patterns": []}


def load_from():
    """Create a loader to load knitting patterns with.

    :return: the loader to load objects with
    :rtype: knittingpattern.Loader.JSONLoader

    Example:

    .. code:: python

       import knittingpattern, webbrowser
       k = knittingpattern.load_from().example("Cafe.json")
       webbrowser.open(k.to_svg(25).temporary_path(".svg"))

    """
    from .ParsingSpecification import new_knitting_pattern_set_loader
    return new_knitting_pattern_set_loader()


def load_from_object(object_):
    """Load a knitting pattern from an object.

    :rtype: knittingpattern.KnittingPatternSet.KnittingPatternSet
    """
    return load_from().object(object_)


def load_from_string(string):
    """Load a knitting pattern from a string.

    :rtype: knittingpattern.KnittingPatternSet.KnittingPatternSet
    """
    return load_from().string(string)


def load_from_file(file):
    """Load a knitting pattern from a file-like object.

    :rtype: knittingpattern.KnittingPatternSet.KnittingPatternSet
    """
    return load_from().file(file)


def load_from_path(path):
    """Load a knitting pattern from a file behind located at `path`.

    :rtype: knittingpattern.KnittingPatternSet.KnittingPatternSet
    """
    return load_from().path(path)


def load_from_url(url):
    """Load a knitting pattern from a url.

    :rtype: knittingpattern.KnittingPatternSet.KnittingPatternSet
    """
    return load_from().url(url)


def load_from_relative_file(module, path_relative_to):
    """Load a knitting pattern from a path relative to a module.

    :param str module: can be a module's file, a module's name or
      a module's path.
    :param str path_relative_to: is the path relative to the modules location.
      The result is loaded from this.

    :rtype: knittingpattern.KnittingPatternSet.KnittingPatternSet
    """
    return load_from().relative_file(module, path_relative_to)


def convert_from_image(colors=("white", "black")):
    """Convert and image to a knitting pattern.

    :return: a loader
    :rtype: knittingpattern.Loader.PathLoader
    :param tuple colors: the colors to convert to

    .. code:: python

        convert_from_image().path("pattern.png").path("pattern.json")
        convert_from_image().path("pattern.png").knitting_pattern()

    .. seealso:: :mod:`knittingoattern.convert.image_to_knitting_pattern`
    """
    from .convert.image_to_knittingpattern import \
        convert_image_to_knitting_pattern
    return convert_image_to_knitting_pattern(colors=colors)


def new_knitting_pattern(id_, name=None):
    """Create a new knitting pattern.

    :return: a new empty knitting pattern.
    :param id_: the id of the knitting pattern
    :param name: the name of the knitting pattern or :obj:`None` if the
      :paramref:`id_` should be used
    :rtype: knittingpattern.KnittingPattern.KnittingPattern

    .. seealso:: :meth:`KnittingPatternSet.add_new_pattern()
      <knittingpattern.KnittingPatternSet.KnittingPatternSet.add_new_pattern>`
    """
    knitting_pattern_set = new_knitting_pattern_set()
    return knitting_pattern_set.add_new_pattern(id_, name)


def new_knitting_pattern_set():
    """Create a new, empty knitting pattern set.

    :rtype: knittingpattern.KnittingPatternSet.KnittingPatternSet
    :return: a new, empty knitting pattern set
    """
    return load_from_object(EMPTY_KNITTING_PATTERN_SET)

__all__ = ["load_from_object", "load_from_string", "load_from_file",
           "load_from_path", "load_from_url", "load_from_relative_file",
           "convert_from_image", "load_from", "new_knitting_pattern",
           "new_knitting_pattern_set"]


================================================
FILE: knittingpattern/convert/AYABPNGBuilder.py
================================================
"""Convert knitting patterns to png files.

These png files are used to be fed into the ayab-desktop software.
They only contain which meshes will be knit with a contrast color.
They just contain colors.
"""
import webcolors
import PIL.Image
from .color import convert_color_to_rrggbb


class AYABPNGBuilder(object):
    """Convert knitting patterns to png files that only contain the color
    information and ``(x, y)`` coordinates.

    .. _png-color:

    Througout this class the term `color` refers to either

    - a valid html5 color name such as ``"black"``, ``"white"``
    - colors of the form ``"#RGB"``, ``"#RRGGBB"`` and ``"#RRRGGGBBB"``

    """

    def __init__(self, min_x, min_y, max_x, max_y,
                 default_color="white"):
        """Initialize the builder with the bounding box and a default color.

        .. _png-builder-bounds:

        ``min_x <= x < max_x`` and ``min_y <= y < max_y`` are the bounds of the
        instructions.
        Instructions outside the bounds are not rendered.
        Any Pixel that is not set has the :paramref:`default_color`.

        :param int min_x: the lower bound of the x coordinates
        :param int max_x: the upper bound of the x coordinates
        :param int min_y: the lower bound of the y coordinates
        :param int max_y: the upper bound of the y coordinates
        :param default_color: a valid :ref:`color <png-color>`
        """
        self._min_x = min_x
        self._min_y = min_y
        self._max_x = max_x
        self._max_y = max_y
        self._default_color = default_color
        self._image = PIL.Image.new(
            "RGB", (max_x - min_x, max_y - min_y),
            self._convert_to_image_color(default_color))

    def write_to_file(self, file):
        """write the png to the file

        :param file: a file-like object
        """
        self._image.save(file, format="PNG")

    @staticmethod
    def _convert_color_to_rrggbb(color):
        """takes a :ref:`color <png-color>` and converts it into a 24 bit
        color "#RRGGBB"

        """
        return convert_color_to_rrggbb(color)

    def _convert_rrggbb_to_image_color(self, rrggbb):
        """:return: the color that is used by the image"""
        return webcolors.hex_to_rgb(rrggbb)

    def _convert_to_image_color(self, color):
        """:return: a color that can be used by the image"""
        rgb = self._convert_color_to_rrggbb(color)
        return self._convert_rrggbb_to_image_color(rgb)

    def _set_pixel_and_convert_color(self, x, y, color):
        """set the pixel but convert the color before."""
        if color is None:
            return
        color = self._convert_color_to_rrggbb(color)
        self._set_pixel(x, y, color)

    def _set_pixel(self, x, y, color):
        """set the color of the pixel.

        :param color: must be a valid color in the form of "#RRGGBB".
          If you need to convert color, use `_set_pixel_and_convert_color()`.
        """
        if not self.is_in_bounds(x, y):
            return
        rgb = self._convert_rrggbb_to_image_color(color)
        x -= self._min_x
        y -= self._min_y
        self._image.putpixel((x, y), rgb)

    def set_pixel(self, x, y, color):
        """set the pixel at ``(x, y)`` position to :paramref:`color`

        If ``(x, y)`` is out of the :ref:`bounds <png-builder-bounds>`
        this does not change the image.

        .. seealso:: :meth:`set_color_in_grid`
        """
        self._set_pixel_and_convert_color(x, y, color)

    def is_in_bounds(self, x, y):
        """
        :return: whether ``(x, y)`` is inside the :ref:`bounds
          <png-builder-bounds>`
        :rtype: bool
        """
        lower = self._min_x <= x and self._min_y <= y
        upper = self._max_x > x and self._max_y > y
        return lower and upper

    def set_color_in_grid(self, color_in_grid):
        """Set the pixel at the position of the :paramref:`color_in_grid`
        to its color.

        :param color_in_grid: must have the following attributes:

          - ``color`` is the :ref:`color <png-color>` to set the pixel to
          - ``x`` is the x position of the pixel
          - ``y`` is the y position of the pixel

        .. seealso:: :meth:`set_pixel`, :meth:`set_colors_in_grid`
        """
        self._set_pixel_and_convert_color(
            color_in_grid.x, color_in_grid.y, color_in_grid.color)

    def set_colors_in_grid(self, some_colors_in_grid):
        """Same as :meth:`set_color_in_grid` but with a collection of
        colors in grid.

        :param iterable some_colors_in_grid: a collection of colors in grid for
          :meth:`set_color_in_grid`
        """
        for color_in_grid in some_colors_in_grid:
            self._set_pixel_and_convert_color(
                color_in_grid.x, color_in_grid.y, color_in_grid.color)

    @property
    def default_color(self):
        """:return: the :ref:`color <png-color>` of the pixels that are not set

        You can set this color by passing it to the :meth:`constructor
        <__init__>`.
        """
        return self._default_color


__all__ = ["AYABPNGBuilder"]


================================================
FILE: knittingpattern/convert/AYABPNGDumper.py
================================================
"""Dump knitting patterns to PNG files compatible with the AYAB software.

"""

from ..Dumper import ContentDumper
from .Layout import GridLayout
from .AYABPNGBuilder import AYABPNGBuilder


class AYABPNGDumper(ContentDumper):
    """This class converts knitting patterns into PNG files."""

    def __init__(self, function_that_returns_a_knitting_pattern_set):
        """Initialize the Dumper with a
        :paramref:`function_that_returns_a_knitting_pattern_set`.

        :param function_that_returns_a_knitting_pattern_set: a function that
          takes no arguments but returns a
          :class:`knittinpattern.KnittingPatternSet.KnittingPatternSet`

        When a dump is requested, the
        :paramref:`function_that_returns_a_knitting_pattern_set`
        is called and the knitting pattern set is converted and saved to the
        specified location.
        """
        super().__init__(self._dump_knitting_pattern,
                         text_is_expected=False, encoding=None)
        self.__on_dump = function_that_returns_a_knitting_pattern_set

    def _dump_knitting_pattern(self, file):
        """dump a knitting pattern to a file."""
        knitting_pattern_set = self.__on_dump()
        knitting_pattern = knitting_pattern_set.patterns.at(0)
        layout = GridLayout(knitting_pattern)
        builder = AYABPNGBuilder(*layout.bounding_box)
        builder.set_colors_in_grid(layout.walk_instructions())
        builder.write_to_file(file)

    def temporary_path(self, extension=".png"):
        return super().temporary_path(extension=extension)
    temporary_path.__doc__ = ContentDumper.temporary_path.__doc__


__all__ = ["AYABPNGDumper"]


================================================
FILE: knittingpattern/convert/InstructionSVGCache.py
================================================
"""This module provides functionality to cache instruction SVGs."""
from .InstructionToSVG import default_instructions_to_svg
from ..Dumper import SVGDumper
from copy import deepcopy
from collections import namedtuple

_InstructionId = namedtuple("_InstructionId", ["type", "hex_color"])


class InstructionSVGCache(object):

    """This class is a cache for SVG instructions.

    If you plan too use only :meth:`instruction_to_svg_dict`, you are save to
    replace a
    :class:`knittingpsttern.convert.InstructionToSVG.InstructionToSVG` with
    this cache to get faster results.
    """

    def __init__(self, instruction_to_svg=None):
        """Create the InstructionSVGCache.

        :param instruction_to_svg: an
         :class:`~knittingpattern.convert.InstructionToSVG.InstructionToSVG`
         object. If :obj:`None` is given, the
         :func:`default_instructions_to_svg
         <knittingpattern.convert.InstructionToSVG.default_instructions_to_svg>`
         is used.
        """
        if instruction_to_svg is None:
            instruction_to_svg = default_instructions_to_svg()
        self._instruction_to_svg_dict = \
            instruction_to_svg.instruction_to_svg_dict
        self._cache = {}

    def get_instruction_id(self, instruction_or_id):
        """The id that identifies the instruction in this cache.

        :param instruction_or_id: an :class:`instruction
          <knittingpattern.Instruction.Instruction>` or an instruction id
        :return: a :func:`hashable <hash>` object
        :rtype: tuple
        """
        if isinstance(instruction_or_id, tuple):
            return _InstructionId(instruction_or_id)
        return _InstructionId(instruction_or_id.type,
                              instruction_or_id.hex_color)

    def _new_svg_dumper(self, on_dump):
        """Create a new SVGDumper with the function ``on_dump``.

        :rtype: knittingpattern.Dumper.SVGDumper
        """
        return SVGDumper(on_dump)

    def to_svg(self, instruction_or_id,
               i_promise_not_to_change_the_result=False):
        """Return the SVG for an instruction.

        :param instruction_or_id: either an
          :class:`~knittingpattern.Instruction.Instruction` or an id
          returned by :meth:`get_instruction_id`
        :param bool i_promise_not_to_change_the_result:

          - :obj:`False`: the result is copied, you can alter it.
          - :obj:`True`: the result is directly from the cache. If you change
            the result, other calls of this function get the changed result.

        :return: an SVGDumper
        :rtype: knittingpattern.Dumper.SVGDumper
        """
        return self._new_svg_dumper(lambda: self.instruction_to_svg_dict(
            instruction_or_id, not i_promise_not_to_change_the_result))

    def instruction_to_svg_dict(self, instruction_or_id, copy_result=True):
        """Return the SVG dict for the SVGBuilder.

        :param instruction_or_id: the instruction or id, see
          :meth:`get_instruction_id`
        :param bool copy_result: whether to copy the result
        :rtype: dict

        The result is cached.
        """
        instruction_id = self.get_instruction_id(instruction_or_id)
        if instruction_id in self._cache:
            result = self._cache[instruction_id]
        else:
            result = self._instruction_to_svg_dict(instruction_id)
            self._cache[instruction_id] = result
        if copy_result:
            result = deepcopy(result)
        return result


def default_instruction_svg_cache():
    """Return the default InstructionSVGCache.

    :rtype: knittingpattern.convert.InstructionSVGCache.InstructionSVGCache
    """
    global _default_instruction_svg_cache
    if _default_instruction_svg_cache is None:
        _default_instruction_svg_cache = InstructionSVGCache()
    return _default_instruction_svg_cache
_default_instruction_svg_cache = None
default_svg_cache = default_instruction_svg_cache

__all__ = ["InstructionSVGCache", "default_instruction_svg_cache",
           "default_svg_cache"]


================================================
FILE: knittingpattern/convert/InstructionToSVG.py
================================================
"""This module maps instructions to SVG.

Use :func:`default_instructions_to_svg` to load the svg files provided by
this package.
"""
import os
import xmltodict
from knittingpattern.Loader import PathLoader

#:  The string to replace with the pattern name in the SVG file.
REPLACE_IN_DEFAULT_SVG = "{instruction.type}"


class InstructionToSVG(object):
    """This class maps instructions to SVGs."""

    @property
    def _loader_class(self):
        """:return: the loader to load svgs from different locations
        :rtype: knittingpattern.Loader.PathLoader ."""
        return PathLoader

    def __init__(self):
        """create a InstructionToSVG object without arguments."""
        self._instruction_type_to_file_content = {}

    @property
    def load(self):
        """:return: a loader object that allows loading SVG files from
          various sources such as files and folders.
        :rtype: knittingpattern.Loader.PathLoader

        Examples:

        - ``instruction_to_svg.load.path(path)`` loads an SVG from a file named
          path
        - ``instruction_to_svg.load.folder(path)`` loads all SVG files for
          instructions in the folder recursively.
          If multiple files have the same name, the last occurrence is used.

        """
        return self._loader_class(self._process_loaded_object)

    def _process_loaded_object(self, path):
        """process the :paramref:`path`.

        :param str path: the path to load an svg from
        """
        file_name = os.path.basename(path)
        name = os.path.splitext(file_name)[0]
        with open(path) as file:
            string = file.read()
            self._instruction_type_to_file_content[name] = string

    def instruction_to_svg_dict(self, instruction):
        """
        :return: an xml-dictionary with the same content as
          :meth:`instruction_to_svg`.
        """
        instruction_type = instruction.type
        if instruction_type in self._instruction_type_to_file_content:
            svg = self._instruction_type_to_file_content[instruction_type]
            return self._set_fills_in_color_layer(svg, instruction.hex_color)
        return self.default_instruction_to_svg_dict(instruction)

    def instruction_to_svg(self, instruction):
        """:return: an SVG representing the instruction.

        The SVG file is determined by the type attribute of the instruction.
        An instruction of type ``"knit"`` is looked for in a file named
        ``"knit.svg"``.

        Every element inside a group labeled ``"color"`` of mode ``"layer"``
        that has a ``"fill"`` style gets this fill replaced by the color of
        the instruction.
        Example of a recangle that gets filled like the instruction:

        .. code:: xml

            <g inkscape:label="color" inkscape:groupmode="layer">
                <rect style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero"
                      id="rectangle1" width="10" height="10" x="0" y="0" />
            </g>

        If nothing was loaded to display this instruction, a default image is
        be generated by :meth:`default_instruction_to_svg`.
        """
        return xmltodict.unparse(self.instruction_to_svg_dict(instruction))

    def _set_fills_in_color_layer(self, svg_string, color):
        """replaces fill colors in ``<g inkscape:label="color"
        inkscape:groupmode="layer">`` with :paramref:`color`

        :param color: a color fill the objects in the layer with
        """
        structure = xmltodict.parse(svg_string)
        if color is None:
            return structure
        layers = structure["svg"]["g"]
        if not isinstance(layers, list):
            layers = [layers]
        for layer in layers:
            if not isinstance(layer, dict):
                continue
            if layer.get("@inkscape:label") == "color" and \
                    layer.get("@inkscape:groupmode") == "layer":
                for key, elements in layer.items():
                    if key.startswith("@") or key.startswith("#"):
                        continue
                    if not isinstance(elements, list):
                        elements = [elements]
                    for element in elements:
                        style = element.get("@style", None)
                        if style:
                            style = style.split(";")
                            processed_style = []
                            for style_element in style:
                                if style_element.startswith("fill:"):
                                    style_element = "fill:" + color
                                processed_style.append(style_element)
                            style = ";".join(processed_style)
                            element["@style"] = style
        return structure

    def has_svg_for_instruction(self, instruction):
        """:return: whether there is an image for the instruction
        :rtype: bool

        This can be used before :meth:`instruction_to_svg` as it determines
        whether

        - the default value is used (:obj:`False`)
        - or there is a dedicated svg representation (:obj:`True`).

        """
        instruction_type = instruction.type
        return instruction_type in self._instruction_type_to_file_content

    def default_instruction_to_svg(self, instruction):
        """As :meth:`instruction_to_svg` but it only takes the ``default.svg``
        file into account.

        In case no file is found for an instruction in
        :meth:`instruction_to_svg`,
        this method is used to determine the default svg for it.

        The content is created by replacing the text ``{instruction.type}`` in
        the whole svg file named ``default.svg``.

        If no file ``default.svg`` was loaded, an empty string is returned.
        """
        svg_dict = self.default_instruction_to_svg_dict(instruction)
        return xmltodict.unparse(svg_dict)

    def default_instruction_to_svg_dict(self, instruction):
        """Returns an xml-dictionary with the same content as
        :meth:`default_instruction_to_svg`

        If no file ``default.svg`` was loaded, an empty svg-dict is returned.
        """
        instruction_type = instruction.type
        default_type = "default"
        rep_str = "{instruction.type}"
        if default_type not in self._instruction_type_to_file_content:
            return {"svg": ""}
        default_svg = self._instruction_type_to_file_content[default_type]
        default_svg = default_svg.replace(rep_str, instruction_type)
        colored_svg = self._set_fills_in_color_layer(default_svg,
                                                     instruction.hex_color)
        return colored_svg

#: The name of the folder containing the svg files for the default
#: instructions.
DEFAULT_SVG_FOLDER = "instruction-svgs"


def default_instructions_to_svg():
    """load the default set of svg files for instructions

    :return: the default svg files for the instructions in this package
    :rtype: knittingpattern.InstructionToSVG.InstructionToSVG

    """
    instruction_to_svg = InstructionToSVG()
    instruction_to_svg.load.relative_folder(__name__, DEFAULT_SVG_FOLDER)
    return instruction_to_svg

__all__ = ["InstructionToSVG", "default_instructions_to_svg",
           "DEFAULT_SVG_FOLDER"]


================================================
FILE: knittingpattern/convert/KnittingPatternToSVG.py
===========
Download .txt
gitextract_h52otm60/

├── .codeclimate.yml
├── .gitignore
├── .landscape.yaml
├── .travis.yml
├── CONTRIBUTING.rst
├── DeveloperCertificateOfOrigin.txt
├── LICENSE
├── MANIFEST.in
├── README.rst
├── appveyor.yml
├── dev-requirements.in
├── dev-requirements.txt
├── docs/
│   ├── DevelopmentSetup.rst
│   ├── FileFormatSpecification.rst
│   ├── Installation.rst
│   ├── Makefile
│   ├── _static/
│   │   └── .gitignore
│   ├── _templates/
│   │   └── .gitignore
│   ├── conf.py
│   ├── index.rst
│   ├── make.bat
│   ├── make_html.bat
│   ├── reference/
│   │   ├── index.rst
│   │   └── knittingpattern/
│   │       ├── Dumper/
│   │       │   ├── FileWrapper.rst
│   │       │   ├── file.rst
│   │       │   ├── index.rst
│   │       │   ├── init.rst
│   │       │   ├── json.rst
│   │       │   ├── svg.rst
│   │       │   └── xml.rst
│   │       ├── IdCollection.rst
│   │       ├── Instruction.rst
│   │       ├── InstructionLibrary.rst
│   │       ├── KnittingPattern.rst
│   │       ├── KnittingPatternSet.rst
│   │       ├── Loader.rst
│   │       ├── Mesh.rst
│   │       ├── Parser.rst
│   │       ├── ParsingSpecification.rst
│   │       ├── Prototype.rst
│   │       ├── Row.rst
│   │       ├── convert/
│   │       │   ├── AYABPNGBuilder.rst
│   │       │   ├── AYABPNGDumper.rst
│   │       │   ├── InstructionSVGCache.rst
│   │       │   ├── InstructionToSVG.rst
│   │       │   ├── KnittingPatternToSVG.rst
│   │       │   ├── Layout.rst
│   │       │   ├── SVGBuilder.rst
│   │       │   ├── color.rst
│   │       │   ├── image_to_knittingpattern.rst
│   │       │   ├── index.rst
│   │       │   ├── init.rst
│   │       │   └── load_and_dump.rst
│   │       ├── index.rst
│   │       ├── init.rst
│   │       ├── utils.rst
│   │       └── walk.rst
│   └── test/
│       ├── test_docs.py
│       ├── test_documentation_sources_exist.py
│       └── test_sphinx_build.py
├── knittingpattern/
│   ├── Dumper/
│   │   ├── FileWrapper.py
│   │   ├── __init__.py
│   │   ├── file.py
│   │   ├── json.py
│   │   ├── svg.py
│   │   └── xml.py
│   ├── IdCollection.py
│   ├── Instruction.py
│   ├── InstructionLibrary.py
│   ├── KnittingPattern.py
│   ├── KnittingPatternSet.py
│   ├── Loader.py
│   ├── Mesh.py
│   ├── Parser.py
│   ├── ParsingSpecification.py
│   ├── Prototype.py
│   ├── Row.py
│   ├── __init__.py
│   ├── convert/
│   │   ├── AYABPNGBuilder.py
│   │   ├── AYABPNGDumper.py
│   │   ├── InstructionSVGCache.py
│   │   ├── InstructionToSVG.py
│   │   ├── KnittingPatternToSVG.py
│   │   ├── Layout.py
│   │   ├── SVGBuilder.py
│   │   ├── __init__.py
│   │   ├── color.py
│   │   ├── image_to_knittingpattern.py
│   │   ├── load_and_dump.py
│   │   └── test/
│   │       ├── pictures/
│   │       │   └── conversion.tif
│   │       ├── test_AYABPNGBuilder.py
│   │       ├── test_SVGBuilder.py
│   │       ├── test_convert.py
│   │       ├── test_default_instruction_layout.py
│   │       ├── test_default_svgs.py
│   │       ├── test_images.py
│   │       ├── test_instruction_to_svg.py
│   │       ├── test_knittingpattern_to_png.py
│   │       ├── test_layout.py
│   │       ├── test_patterns/
│   │       │   ├── add and remove meshes.json
│   │       │   ├── block4x4.json
│   │       │   ├── cast_on_and_bind_off.json
│   │       │   ├── small-cafe.json
│   │       │   ├── split_up_and_add_rows.json
│   │       │   └── with hole.json
│   │       ├── test_png_to_knittingpattern.py
│   │       └── test_save_as_svg.py
│   ├── examples/
│   │   ├── Cafe.json
│   │   ├── Charlotte.json
│   │   ├── README.md
│   │   ├── all-instructions.json
│   │   ├── block4x4.json
│   │   ├── empty.json
│   │   ├── negative-rendering.json
│   │   └── new-knitting-pattern.py
│   ├── instructions/
│   │   ├── bo.json
│   │   ├── cdd.json
│   │   ├── co.json
│   │   ├── k2tog.json
│   │   ├── knit.json
│   │   ├── purl.json
│   │   ├── skp.json
│   │   └── yo.json
│   ├── test/
│   │   ├── conftest.py
│   │   ├── pattern/
│   │   │   ├── inheritance.json
│   │   │   ├── row_mapping_pattern.json
│   │   │   ├── row_removal_pattern.json
│   │   │   └── single_instruction.json
│   │   ├── test_add_and_remove_instructions.py
│   │   ├── test_change_row_mapping.py
│   │   ├── test_default_instructions.py
│   │   ├── test_dump_json.py
│   │   ├── test_dumper.py
│   │   ├── test_example_code.py
│   │   ├── test_example_rows.py
│   │   ├── test_examples.py
│   │   ├── test_id_collection.py
│   │   ├── test_instruction.py
│   │   ├── test_instruction_library.py
│   │   ├── test_instruction_row_inheritance.py
│   │   ├── test_instructions/
│   │   │   ├── recursion/
│   │   │   │   ├── test_instruction_3.json
│   │   │   │   └── test_instruction_4.json
│   │   │   ├── test_instruction_1.json
│   │   │   └── test_instruction_2.json
│   │   ├── test_knittingpattern.py
│   │   ├── test_load_instructions.py
│   │   ├── test_loader.py
│   │   ├── test_parsing.py
│   │   ├── test_row_instructions.py
│   │   ├── test_row_mapping.py
│   │   ├── test_row_meshes.py
│   │   ├── test_utilities.py
│   │   └── test_walk.py
│   ├── utils.py
│   └── walk.py
├── pylintrc
├── requirements.in
├── requirements.txt
├── setup.cfg
├── setup.py
├── test-requirements.in
└── test-requirements.txt
Download .txt
SYMBOL INDEX (925 symbols across 65 files)

FILE: docs/test/test_docs.py
  function absjoin (line 4) | def absjoin(*args):

FILE: docs/test/test_documentation_sources_exist.py
  function relative_module_path (line 15) | def relative_module_path(absolute_path):
  function module_name_and_doc (line 24) | def module_name_and_doc(relative_path):
  function add_module (line 45) | def add_module(absolute_path):
  function test_module_has_a_documentation_file (line 73) | def test_module_has_a_documentation_file(module):
  function test_documentation_references_module (line 78) | def test_documentation_references_module(module):
  function test_documentation_has_proper_title (line 84) | def test_documentation_has_proper_title(module):
  function create_new_module_documentation (line 90) | def create_new_module_documentation():

FILE: docs/test/test_sphinx_build.py
  function print_bytes (line 21) | def print_bytes(bytes_):
  function sphinx_build (line 30) | def sphinx_build():
  function coverage (line 47) | def coverage(sphinx_build):
  function warnings (line 55) | def warnings(sphinx_build):
  function test_all_methods_are_documented (line 60) | def test_all_methods_are_documented(coverage):
  function test_doc_build_passes_without_warnings (line 66) | def test_doc_build_passes_without_warnings(warnings):

FILE: knittingpattern/Dumper/FileWrapper.py
  class BytesWrapper (line 7) | class BytesWrapper(object):
    method __init__ (line 12) | def __init__(self, text_file, encoding):
    method write (line 24) | def write(self, bytes_):
  class TextWrapper (line 30) | class TextWrapper(object):
    method __init__ (line 35) | def __init__(self, binary_file, encoding):
    method write (line 47) | def write(self, string):

FILE: knittingpattern/Dumper/file.py
  class ContentDumper (line 7) | class ContentDumper(object):
    method __init__ (line 24) | def __init__(self, on_dump, text_is_expected=True, encoding="UTF-8"):
    method encoding (line 51) | def encoding(self):
    method string (line 56) | def string(self):
    method _string (line 63) | def _string(self):
    method bytes (line 70) | def bytes(self):
    method _bytes (line 77) | def _bytes(self):
    method file (line 84) | def file(self, file=None):
    method _file (line 102) | def _file(self, file):
    method binary_file (line 109) | def binary_file(self, file=None):
    method _binary_file (line 116) | def _binary_file(self, file):
    method _mode_and_encoding_for_open (line 123) | def _mode_and_encoding_for_open(self):
    method path (line 129) | def path(self, path):
    method _path (line 136) | def _path(self, path):
    method _temporary_file (line 142) | def _temporary_file(self, delete):
    method temporary_path (line 149) | def temporary_path(self, extension=""):
    method temporary_file (line 165) | def temporary_file(self, delete_when_closed=True):
    method binary_temporary_file (line 186) | def binary_temporary_file(self, delete_when_closed=True):
    method _binary_temporary_file (line 191) | def _binary_temporary_file(self, delete):
    method __repr__ (line 197) | def __repr__(self):

FILE: knittingpattern/Dumper/json.py
  class JSONDumper (line 6) | class JSONDumper(ContentDumper):
    method __init__ (line 10) | def __init__(self, on_dump):
    method object (line 18) | def object(self):
    method _dump_to_file (line 22) | def _dump_to_file(self, file):
    method knitting_pattern (line 26) | def knitting_pattern(self, specification=None):

FILE: knittingpattern/Dumper/svg.py
  class SVGDumper (line 6) | class SVGDumper(XMLDumper):
    method kivy_svg (line 10) | def kivy_svg(self):

FILE: knittingpattern/Dumper/xml.py
  class XMLDumper (line 6) | class XMLDumper(ContentDumper):
    method __init__ (line 10) | def __init__(self, on_dump):
    method object (line 18) | def object(self):
    method _dump_to_file (line 22) | def _dump_to_file(self, file):

FILE: knittingpattern/IdCollection.py
  class IdCollection (line 6) | class IdCollection(object):
    method __init__ (line 9) | def __init__(self):
    method append (line 16) | def append(self, item):
    method at (line 23) | def at(self, index):
    method __getitem__ (line 33) | def __getitem__(self, id_):
    method __bool__ (line 50) | def __bool__(self):
    method __iter__ (line 56) | def __iter__(self):
    method __len__ (line 64) | def __len__(self):
    method first (line 69) | def first(self):

FILE: knittingpattern/Instruction.py
  class Instruction (line 59) | class Instruction(Prototype):
    method id (line 78) | def id(self):
    method type (line 87) | def type(self):
    method color (line 103) | def color(self):
    method colors (line 112) | def colors(self):
    method description (line 122) | def description(self):
    method number_of_consumed_meshes (line 131) | def number_of_consumed_meshes(self):
    method number_of_produced_meshes (line 142) | def number_of_produced_meshes(self):
    method has_color (line 152) | def has_color(self):
    method does_knit (line 160) | def does_knit(self):
    method does_purl (line 168) | def does_purl(self):
    method produces_meshes (line 176) | def produces_meshes(self):
    method consumes_meshes (line 186) | def consumes_meshes(self):
    method render_z (line 197) | def render_z(self):
    method hex_color (line 207) | def hex_color(self):
    method to_svg (line 217) | def to_svg(self, converter=None):
  class InstructionInRow (line 234) | class InstructionInRow(Instruction):
    method __init__ (line 241) | def __init__(self, row, spec):
    method transfer_to_row (line 260) | def transfer_to_row(self, new_row):
    method _new_produced_mesh (line 273) | def _new_produced_mesh(self):
    method _new_consumed_mesh (line 278) | def _new_consumed_mesh(self):
    method row (line 283) | def row(self):
    method is_in_row (line 291) | def is_in_row(self):
    method get_index_in_row (line 301) | def get_index_in_row(self):
    method index_in_row (line 324) | def index_in_row(self):
    method row_instructions (line 346) | def row_instructions(self):
    method next_instruction_in_row (line 356) | def next_instruction_in_row(self):
    method previous_instruction_in_row (line 373) | def previous_instruction_in_row(self):
    method _instruction_not_found_message (line 390) | def _instruction_not_found_message(self):
    method _raise_not_found_error (line 402) | def _raise_not_found_error(self):
    method index_of_first_produced_mesh_in_row (line 413) | def index_of_first_produced_mesh_in_row(self):
    method index_of_last_produced_mesh_in_row (line 441) | def index_of_last_produced_mesh_in_row(self):
    method index_of_first_consumed_mesh_in_row (line 459) | def index_of_first_consumed_mesh_in_row(self):
    method index_of_last_consumed_mesh_in_row (line 475) | def index_of_last_consumed_mesh_in_row(self):
    method produced_meshes (line 485) | def produced_meshes(self):
    method consumed_meshes (line 502) | def consumed_meshes(self):
    method __repr__ (line 518) | def __repr__(self):
    method producing_instructions (line 537) | def producing_instructions(self):
    method consuming_instructions (line 550) | def consuming_instructions(self):
    method color (line 563) | def color(self):
    method last_produced_mesh (line 575) | def last_produced_mesh(self):
    method last_consumed_mesh (line 587) | def last_consumed_mesh(self):
    method first_produced_mesh (line 599) | def first_produced_mesh(self):
    method first_consumed_mesh (line 611) | def first_consumed_mesh(self):
  class InstructionNotFoundInRow (line 623) | class InstructionNotFoundInRow(ValueError):

FILE: knittingpattern/InstructionLibrary.py
  class InstructionLibrary (line 13) | class InstructionLibrary(object):
    method _loader_class (line 21) | def _loader_class(self):
    method _instruction_class (line 28) | def _instruction_class(self):
    method __init__ (line 33) | def __init__(self):
    method load (line 43) | def load(self):
    method _process_loaded_object (line 64) | def _process_loaded_object(self, obj):
    method add_instruction (line 71) | def add_instruction(self, specification):
    method as_instruction (line 82) | def as_instruction(self, specification):
    method __getitem__ (line 98) | def __getitem__(self, instruction_type):
    method loaded_types (line 106) | def loaded_types(self):
  class DefaultInstructions (line 115) | class DefaultInstructions(InstructionLibrary):
    method __init__ (line 122) | def __init__(self):
  function default_instructions (line 131) | def default_instructions():

FILE: knittingpattern/KnittingPattern.py
  class KnittingPattern (line 13) | class KnittingPattern(object):
    method __init__ (line 21) | def __init__(self, id_, name, rows, parser):
    method id (line 38) | def id(self):
    method name (line 45) | def name(self):
    method rows (line 50) | def rows(self):
    method add_row (line 58) | def add_row(self, id_):
    method rows_in_knit_order (line 67) | def rows_in_knit_order(self):
    method instruction_colors (line 78) | def instruction_colors(self):

FILE: knittingpattern/KnittingPatternSet.py
  class KnittingPatternSet (line 11) | class KnittingPatternSet(object):
    method __init__ (line 23) | def __init__(self, type_, version, patterns, parser, comment=None):
    method version (line 47) | def version(self):
    method type (line 58) | def type(self):
    method patterns (line 69) | def patterns(self):
    method comment (line 80) | def comment(self):
    method to_ayabpng (line 88) | def to_ayabpng(self):
    method to_svg (line 105) | def to_svg(self, zoom):
    method add_new_pattern (line 133) | def add_new_pattern(self, id_, name=None):
    method first (line 149) | def first(self):

FILE: knittingpattern/Loader.py
  function identity (line 11) | def identity(object_):
  function true (line 17) | def true(_):
  class PathLoader (line 23) | class PathLoader(object):
    method __init__ (line 30) | def __init__(self, process=identity, chooses_path=true):
    method folder (line 45) | def folder(self, folder):
    method chooses_path (line 64) | def chooses_path(self, path):
    method path (line 72) | def path(self, path):
    method _relative_to_absolute (line 80) | def _relative_to_absolute(self, module_location, folder):
    method relative_folder (line 100) | def relative_folder(self, module, folder):
    method relative_file (line 122) | def relative_file(self, module, file):
    method choose_paths (line 138) | def choose_paths(self, paths):
    method example (line 144) | def example(self, relative_path):
    method examples (line 156) | def examples(self):
  class ContentLoader (line 168) | class ContentLoader(PathLoader):
    method string (line 175) | def string(self, string):
    method file (line 181) | def file(self, file):
    method path (line 190) | def path(self, path):
    method url (line 198) | def url(self, url, encoding="UTF-8"):
  class JSONLoader (line 214) | class JSONLoader(ContentLoader):
    method object (line 221) | def object(self, object_):
    method string (line 229) | def string(self, string):

FILE: knittingpattern/Mesh.py
  class Mesh (line 5) | class Mesh(metaclass=ABCMeta):
    method _producing_instruction_and_index (line 20) | def _producing_instruction_and_index(self):
    method _producing_row_and_index (line 24) | def _producing_row_and_index(self):
    method _consuming_instruction_and_index (line 28) | def _consuming_instruction_and_index(self):
    method _consuming_row_and_index (line 32) | def _consuming_row_and_index(self):
    method _is_produced (line 36) | def _is_produced(self):
    method _is_consumed (line 40) | def _is_consumed(self):
    method _is_consumed_mesh (line 44) | def _is_consumed_mesh(self):
    method _disconnect (line 51) | def _disconnect(self):
    method _connect_to (line 55) | def _connect_to(self, other_mesh):
    method _as_produced_mesh (line 59) | def _as_produced_mesh(self):
    method _as_consumed_mesh (line 63) | def _as_consumed_mesh(self):
    method _is_connected_to (line 67) | def _is_connected_to(self, other_mesh):
    method _assert_is_produced (line 70) | def _assert_is_produced(self):
    method _assert_is_consumed (line 73) | def _assert_is_consumed(self):
    method is_produced (line 76) | def is_produced(self):
    method is_consumed (line 92) | def is_consumed(self):
    method index_in_producing_instruction (line 109) | def index_in_producing_instruction(self):
    method producing_instruction (line 131) | def producing_instruction(self):
    method producing_row (line 146) | def producing_row(self):
    method index_in_producing_row (line 161) | def index_in_producing_row(self):
    method index_in_consuming_row (line 181) | def index_in_consuming_row(self):
    method consuming_row (line 202) | def consuming_row(self):
    method consuming_instruction (line 217) | def consuming_instruction(self):
    method index_in_consuming_instruction (line 232) | def index_in_consuming_instruction(self):
    method is_knit (line 253) | def is_knit(self):
    method __repr__ (line 264) | def __repr__(self):
    method disconnect (line 296) | def disconnect(self):
    method connect_to (line 304) | def connect_to(self, other_mesh):
    method is_connected (line 318) | def is_connected(self):
    method as_produced_mesh (line 326) | def as_produced_mesh(self):
    method as_consumed_mesh (line 345) | def as_consumed_mesh(self):
    method is_mesh (line 350) | def is_mesh(self):
    method is_connected_to (line 358) | def is_connected_to(self, other_mesh):
    method can_connect_to (line 363) | def can_connect_to(self, other):
  class ProducedMesh (line 371) | class ProducedMesh(Mesh):
    method __init__ (line 375) | def __init__(self, producing_instruction,
    method _producing_instruction_and_index (line 397) | def _producing_instruction_and_index(self):
    method _producing_row_and_index (line 400) | def _producing_row_and_index(self):
    method _consuming_instruction_and_index (line 406) | def _consuming_instruction_and_index(self):
    method _consuming_row_and_index (line 409) | def _consuming_row_and_index(self):
    method _is_produced (line 412) | def _is_produced(self):
    method _is_consumed (line 415) | def _is_consumed(self):
    method _is_consumed_mesh (line 418) | def _is_consumed_mesh(self):
    method _disconnect (line 421) | def _disconnect(self):
    method _connect_to (line 426) | def _connect_to(self, other_mesh):
    method _as_produced_mesh (line 431) | def _as_produced_mesh(self):
    method _as_consumed_mesh (line 434) | def _as_consumed_mesh(self):
    method _is_connected_to (line 438) | def _is_connected_to(self, other_mesh):
  class ConsumedMesh (line 442) | class ConsumedMesh(Mesh):
    method __init__ (line 445) | def __init__(self, consuming_instruction,
    method _producing_instruction_and_index (line 467) | def _producing_instruction_and_index(self):
    method _producing_row_and_index (line 470) | def _producing_row_and_index(self):
    method _consuming_instruction_and_index (line 473) | def _consuming_instruction_and_index(self):
    method _consuming_row_and_index (line 476) | def _consuming_row_and_index(self):
    method _is_produced (line 483) | def _is_produced(self):
    method _is_consumed (line 486) | def _is_consumed(self):
    method _is_consumed_mesh (line 489) | def _is_consumed_mesh(self):
    method _disconnect (line 492) | def _disconnect(self):
    method _disconnected (line 496) | def _disconnected(self):
    method _connect_to (line 499) | def _connect_to(self, other_mesh):
    method _connect_to_produced_mesh (line 503) | def _connect_to_produced_mesh(self, produced_mesh):
    method _as_produced_mesh (line 508) | def _as_produced_mesh(self):
    method _as_consumed_mesh (line 512) | def _as_consumed_mesh(self):
    method _is_connected_to (line 515) | def _is_connected_to(self, other_mesh):

FILE: knittingpattern/Parser.py
  class ParsingError (line 27) | class ParsingError(ValueError):
  class Parser (line 36) | class Parser(object):
    method __init__ (line 40) | def __init__(self, specification):
    method _start (line 51) | def _start(self):
    method _to_id (line 61) | def _to_id(id_):
    method _error (line 68) | def _error(self, text):
    method knitting_pattern_set (line 76) | def knitting_pattern_set(self, values):
    method _finish_inheritance (line 92) | def _finish_inheritance(self):
    method _delay_inheritance (line 99) | def _delay_inheritance(self, prototype, parent_id):
    method _finish_instructions (line 107) | def _finish_instructions(self):
    method _delay_instructions (line 114) | def _delay_instructions(self, row):
    method _new_pattern_collection (line 122) | def _new_pattern_collection(self):
    method new_row_collection (line 130) | def new_row_collection(self):
    method _fill_pattern_collection (line 138) | def _fill_pattern_collection(self, pattern_collection, values):
    method _row (line 145) | def _row(self, values):
    method new_row (line 155) | def new_row(self, id_):
    method instruction_in_row (line 164) | def instruction_in_row(self, row, specification):
    method _pattern (line 174) | def _pattern(self, base):
    method new_pattern (line 184) | def new_pattern(self, id_, name, rows=None):
    method _rows (line 194) | def _rows(self, spec):
    method _connect_rows (line 201) | def _connect_rows(self, connections):
    method _get_type (line 231) | def _get_type(self, values):
    method _get_version (line 243) | def _get_version(self, values):
    method _create_pattern_set (line 247) | def _create_pattern_set(self, pattern, values):
  function default_parser (line 257) | def default_parser():

FILE: knittingpattern/ParsingSpecification.py
  class ParsingSpecification (line 36) | class ParsingSpecification(object):
    method __init__ (line 45) | def __init__(self,
  class DefaultSpecification (line 69) | class DefaultSpecification(ParsingSpecification):
    method __init__ (line 77) | def __init__(self):
    method __repr__ (line 82) | def __repr__(cls):
  function new_knitting_pattern_set_loader (line 91) | def new_knitting_pattern_set_loader(specification=DefaultSpecification()):

FILE: knittingpattern/Prototype.py
  class Prototype (line 6) | class Prototype(object):
    method __init__ (line 16) | def __init__(self, specification, inherited_values=()):
    method get (line 36) | def get(self, key, default=None):
    method __getitem__ (line 47) | def __getitem__(self, key):
    method __contains__ (line 61) | def __contains__(self, key):
    method inherit_from (line 73) | def inherit_from(self, new_specification):

FILE: knittingpattern/Row.py
  class Row (line 20) | class Row(Prototype):
    method __init__ (line 28) | def __init__(self, row_id, values, parser):
    method _instructions_changed (line 46) | def _instructions_changed(self, change):
    method id (line 57) | def id(self):
    method instructions (line 65) | def instructions(self):
    method number_of_produced_meshes (line 75) | def number_of_produced_meshes(self):
    method number_of_consumed_meshes (line 90) | def number_of_consumed_meshes(self):
    method produced_meshes (line 105) | def produced_meshes(self):
    method consumed_meshes (line 116) | def consumed_meshes(self):
    method __repr__ (line 121) | def __repr__(self):
    method color (line 130) | def color(self):
    method instruction_colors (line 138) | def instruction_colors(self):
    method last_produced_mesh (line 148) | def last_produced_mesh(self):
    method last_consumed_mesh (line 163) | def last_consumed_mesh(self):
    method first_produced_mesh (line 178) | def first_produced_mesh(self):
    method first_consumed_mesh (line 193) | def first_consumed_mesh(self):
    method rows_before (line 208) | def rows_before(self):
    method rows_after (line 225) | def rows_after(self):
    method first_instruction (line 242) | def first_instruction(self):
    method last_instruction (line 251) | def last_instruction(self):

FILE: knittingpattern/__init__.py
  function load_from (line 16) | def load_from():
  function load_from_object (line 35) | def load_from_object(object_):
  function load_from_string (line 43) | def load_from_string(string):
  function load_from_file (line 51) | def load_from_file(file):
  function load_from_path (line 59) | def load_from_path(path):
  function load_from_url (line 67) | def load_from_url(url):
  function load_from_relative_file (line 75) | def load_from_relative_file(module, path_relative_to):
  function convert_from_image (line 88) | def convert_from_image(colors=("white", "black")):
  function new_knitting_pattern (line 107) | def new_knitting_pattern(id_, name=None):
  function new_knitting_pattern_set (line 123) | def new_knitting_pattern_set():

FILE: knittingpattern/convert/AYABPNGBuilder.py
  class AYABPNGBuilder (line 12) | class AYABPNGBuilder(object):
    method __init__ (line 25) | def __init__(self, min_x, min_y, max_x, max_y,
    method write_to_file (line 51) | def write_to_file(self, file):
    method _convert_color_to_rrggbb (line 59) | def _convert_color_to_rrggbb(color):
    method _convert_rrggbb_to_image_color (line 66) | def _convert_rrggbb_to_image_color(self, rrggbb):
    method _convert_to_image_color (line 70) | def _convert_to_image_color(self, color):
    method _set_pixel_and_convert_color (line 75) | def _set_pixel_and_convert_color(self, x, y, color):
    method _set_pixel (line 82) | def _set_pixel(self, x, y, color):
    method set_pixel (line 95) | def set_pixel(self, x, y, color):
    method is_in_bounds (line 105) | def is_in_bounds(self, x, y):
    method set_color_in_grid (line 115) | def set_color_in_grid(self, color_in_grid):
    method set_colors_in_grid (line 130) | def set_colors_in_grid(self, some_colors_in_grid):
    method default_color (line 142) | def default_color(self):

FILE: knittingpattern/convert/AYABPNGDumper.py
  class AYABPNGDumper (line 10) | class AYABPNGDumper(ContentDumper):
    method __init__ (line 13) | def __init__(self, function_that_returns_a_knitting_pattern_set):
    method _dump_knitting_pattern (line 30) | def _dump_knitting_pattern(self, file):
    method temporary_path (line 39) | def temporary_path(self, extension=".png"):

FILE: knittingpattern/convert/InstructionSVGCache.py
  class InstructionSVGCache (line 10) | class InstructionSVGCache(object):
    method __init__ (line 20) | def __init__(self, instruction_to_svg=None):
    method get_instruction_id (line 36) | def get_instruction_id(self, instruction_or_id):
    method _new_svg_dumper (line 49) | def _new_svg_dumper(self, on_dump):
    method to_svg (line 56) | def to_svg(self, instruction_or_id,
    method instruction_to_svg_dict (line 75) | def instruction_to_svg_dict(self, instruction_or_id, copy_result=True):
  function default_instruction_svg_cache (line 96) | def default_instruction_svg_cache():

FILE: knittingpattern/convert/InstructionToSVG.py
  class InstructionToSVG (line 14) | class InstructionToSVG(object):
    method _loader_class (line 18) | def _loader_class(self):
    method __init__ (line 23) | def __init__(self):
    method load (line 28) | def load(self):
    method _process_loaded_object (line 44) | def _process_loaded_object(self, path):
    method instruction_to_svg_dict (line 55) | def instruction_to_svg_dict(self, instruction):
    method instruction_to_svg (line 66) | def instruction_to_svg(self, instruction):
    method _set_fills_in_color_layer (line 90) | def _set_fills_in_color_layer(self, svg_string, color):
    method has_svg_for_instruction (line 125) | def has_svg_for_instruction(self, instruction):
    method default_instruction_to_svg (line 139) | def default_instruction_to_svg(self, instruction):
    method default_instruction_to_svg_dict (line 155) | def default_instruction_to_svg_dict(self, instruction):
  function default_instructions_to_svg (line 177) | def default_instructions_to_svg():

FILE: knittingpattern/convert/KnittingPatternToSVG.py
  class KnittingPatternToSVG (line 10) | class KnittingPatternToSVG(object):
    method __init__ (line 17) | def __init__(self, knittingpattern, layout, instruction_to_svg, builder,
    method build_SVG_dict (line 39) | def build_SVG_dict(self):
    method _register_instruction_in_defs (line 74) | def _register_instruction_in_defs(self, instruction):
    method _make_definition (line 99) | def _make_definition(self, svg_dict, instruction_id):
    method _compute_scale (line 118) | def _compute_scale(self, instruction_id, svg_dict):

FILE: knittingpattern/convert/Layout.py
  class InGrid (line 27) | class InGrid(object):
    method __init__ (line 31) | def __init__(self, position):
    method x (line 36) | def x(self):
    method y (line 43) | def y(self):
    method xy (line 50) | def xy(self):
    method yx (line 57) | def yx(self):
    method width (line 64) | def width(self):
    method height (line 72) | def height(self):
    method row (line 79) | def row(self):
    method bounding_box (line 86) | def bounding_box(self):
    method id (line 95) | def id(self):
  class InstructionInGrid (line 100) | class InstructionInGrid(InGrid):
    method __init__ (line 104) | def __init__(self, instruction, position):
    method _width (line 115) | def _width(self):
    method instruction (line 125) | def instruction(self):
    method color (line 134) | def color(self):
    method _row (line 141) | def _row(self):
  class RowInGrid (line 146) | class RowInGrid(InGrid):
    method __init__ (line 149) | def __init__(self, row, position):
    method _width (line 155) | def _width(self):
    method instructions (line 160) | def instructions(self):
    method _bounding_box (line 177) | def _bounding_box(self):
    method _id (line 186) | def _id(self):
  function identity (line 190) | def identity(object_):
  class _RecursiveWalk (line 195) | class _RecursiveWalk(object):
    method __init__ (line 199) | def __init__(self, first_instruction):
    method _expand (line 207) | def _expand(self, row, consumed_position, passed):
    method _step (line 211) | def _step(self, row, position, passed):
    method _expand_consumed_mesh (line 224) | def _expand_consumed_mesh(self, mesh, mesh_index, row_position, passed):
    method _expand_produced_mesh (line 235) | def _expand_produced_mesh(self, mesh, mesh_index, row_position, passed):
    method _row_should_be_placed (line 246) | def _row_should_be_placed(self, row, position):
    method _place_row (line 251) | def _place_row(self, row, position):
    method _walk (line 255) | def _walk(self):
    method instruction_in_grid (line 261) | def instruction_in_grid(self, instruction):
    method row_in_grid (line 268) | def row_in_grid(self, row):
  class Connection (line 273) | class Connection(object):
    method __init__ (line 276) | def __init__(self, start, stop):
    method start (line 285) | def start(self):
    method stop (line 292) | def stop(self):
    method is_visible (line 298) | def is_visible(self):
  class GridLayout (line 308) | class GridLayout(object):
    method __init__ (line 311) | def __init__(self, pattern):
    method walk_instructions (line 322) | def walk_instructions(self, mapping=identity):
    method walk_rows (line 338) | def walk_rows(self, mapping=identity):
    method walk_connections (line 348) | def walk_connections(self, mapping=identity):
    method bounding_box (line 369) | def bounding_box(self):
    method row_in_grid (line 380) | def row_in_grid(self, row):

FILE: knittingpattern/convert/SVGBuilder.py
  class SVGBuilder (line 25) | class SVGBuilder(object):
    method __init__ (line 32) | def __init__(self):
    method bounding_box (line 43) | def bounding_box(self):
    method bounding_box (line 60) | def bounding_box(self, bbox):
    method place (line 71) | def place(self, x, y, svg, layer_id):
    method place_svg_dict (line 85) | def place_svg_dict(self, x, y, svg_dict, layer_id, group=None):
    method place_svg_use_coords (line 104) | def place_svg_use_coords(self, x, y, symbol_id, layer_id, group=None):
    method place_svg_use (line 121) | def place_svg_use(self, symbol_id, layer_id, group=None):
    method _get_layer (line 129) | def _get_layer(self, layer_id):
    method insert_defs (line 148) | def insert_defs(self, defs):
    method get_svg_dict (line 166) | def get_svg_dict(self):
    method write_to_file (line 170) | def write_to_file(self, file):

FILE: knittingpattern/convert/color.py
  function convert_color_to_rrggbb (line 5) | def convert_color_to_rrggbb(color):

FILE: knittingpattern/convert/image_to_knittingpattern.py
  function convert_image_to_knitting_pattern (line 12) | def convert_image_to_knitting_pattern(path, colors=("white", "black")):

FILE: knittingpattern/convert/load_and_dump.py
  function load_and_dump (line 9) | def load_and_dump(create_loader, create_dumper, load_and_dump_):
  function decorate_load_and_dump (line 43) | def decorate_load_and_dump(create_loader, create_dumper):

FILE: knittingpattern/convert/test/test_AYABPNGBuilder.py
  function builder (line 15) | def builder():
  class TestColorConversion (line 19) | class TestColorConversion(object):
    method convert (line 27) | def convert(self):
    method test_convert_24_bit (line 30) | def test_convert_24_bit(self, convert):
    method test_convert_blue (line 33) | def test_convert_blue(self, convert):
    method test_can_convert_anything_to_color (line 36) | def test_can_convert_anything_to_color(self, convert):
  class TestBounds (line 40) | class TestBounds(object):
    method test_inside (line 44) | def test_inside(self, builder, x, y):
    method test_outside (line 49) | def test_outside(self, builder, x, y):
  class TestSetPixel (line 53) | class TestSetPixel(object):
    method set (line 56) | def set(self):
    method patched (line 60) | def patched(self, builder, set):
    method test_set_pixel (line 64) | def test_set_pixel(self, patched, set):
    method test_set_pixel_converts_color (line 68) | def test_set_pixel_converts_color(self, patched, set):
    method test_set_with_instruction (line 72) | def test_set_with_instruction(self, patched, set):
    method test_call_many_instructions (line 76) | def test_call_many_instructions(self, patched, set):
    method test_setiing_color_none_does_nothing (line 86) | def test_setiing_color_none_does_nothing(self, patched, set):
  class TestSavingAsPNG (line 97) | class TestSavingAsPNG(object):
    method image_path (line 100) | def image_path(self):
    method builder (line 104) | def builder(self, image_path):
    method image (line 118) | def image(self, image_path, builder):
    method test_pixels_are_set (line 121) | def test_pixels_are_set(self, image):
    method test_bbox_is_3x3 (line 126) | def test_bbox_is_3x3(self, image):
    method test_other_pixels_have_default_color (line 129) | def test_other_pixels_have_default_color(self, image):
  class TestDefaultColor (line 133) | class TestDefaultColor(object):
    method default_color (line 136) | def default_color(self, builder):
    method test_can_change_default_color (line 139) | def test_can_change_default_color(self):
    method test_default_color_is_white (line 143) | def test_default_color_is_white(self, default_color):

FILE: knittingpattern/convert/test/test_SVGBuilder.py
  function file (line 9) | def file():
  function builder (line 14) | def builder():
  function svg (line 21) | def svg(builder, file):
  function svg1 (line 32) | def svg1(builder, svg):
  function row1 (line 44) | def row1(svg1):
  function row2 (line 49) | def row2(svg1):
  function instruction1 (line 54) | def instruction1(row1):
  function instruction2 (line 59) | def instruction2(row1):
  function instruction3 (line 64) | def instruction3(row1):
  function instruction21 (line 69) | def instruction21(row2):
  function instruction22 (line 74) | def instruction22(row2):
  function instruction23 (line 79) | def instruction23(row2):
  function test_rendering_nothing_is_a_valid_xml (line 83) | def test_rendering_nothing_is_a_valid_xml(builder, file):
  function test_rendering_nothing_is_an_svg (line 91) | def test_rendering_nothing_is_an_svg(builder, file):
  function test_translate_to_right_position (line 99) | def test_translate_to_right_position(instruction1):
  function test_row_has_id (line 103) | def test_row_has_id(row1):
  function test_row_is_displayed_correctly_by_inkscape (line 107) | def test_row_is_displayed_correctly_by_inkscape(row1):
  function test_content_is_in_group (line 112) | def test_content_is_in_group(instruction1):
  function test_row_contains_several_instructions (line 116) | def test_row_contains_several_instructions(row1, row2):
  function test_instruction2_is_translated (line 121) | def test_instruction2_is_translated(instruction2):
  function test_instruction3_is_translated (line 125) | def test_instruction3_is_translated(instruction3):
  function test_instruction21_is_translated (line 129) | def test_instruction21_is_translated(instruction21):
  function test_instruction22_is_translated (line 133) | def test_instruction22_is_translated(instruction22):
  function test_instruction23_is_translated (line 137) | def test_instruction23_is_translated(instruction23):
  function test_bounding_box (line 141) | def test_bounding_box(builder):
  function test_viewport_is_bounding_box (line 145) | def test_viewport_is_bounding_box(svg1):
  function test_width (line 149) | def test_width(svg1):
  function test_height (line 153) | def test_height(svg1):

FILE: knittingpattern/convert/test/test_convert.py
  function parse_file (line 22) | def parse_file(file):
  function parse_string (line 30) | def parse_string(string):

FILE: knittingpattern/convert/test/test_default_instruction_layout.py
  function default (line 7) | def default():
  function test_knit_has_no_z_index (line 11) | def test_knit_has_no_z_index(default):
  function test_yo_has_z_index (line 15) | def test_yo_has_z_index(default):

FILE: knittingpattern/convert/test/test_default_svgs.py
  function default (line 12) | def default():
  function test_default_instruction_is_not_the_same (line 16) | def test_default_instruction_is_not_the_same(default):
  function test_instructions_have_svg (line 22) | def test_instructions_have_svg(default, instruction):
  function test_default_does_not_have_all_instructions (line 26) | def test_default_does_not_have_all_instructions(default):

FILE: knittingpattern/convert/test/test_images.py
  function title (line 13) | def title(content):
  function is_knit (line 20) | def is_knit(content):
  function is_purl (line 24) | def is_purl(content):
  function is_yo (line 28) | def is_yo(content):
  function is_k2tog (line 32) | def is_k2tog(content):
  function is_default (line 36) | def is_default(content):
  function read (line 40) | def read(path):
  function test_tests_work_on_corresponding_file (line 55) | def test_tests_work_on_corresponding_file(path, test):
  function test_tests_do_not_work_on_other_files (line 65) | def test_tests_do_not_work_on_other_files(path, test):
  function test_default_content_has_identifier_in_place (line 69) | def test_default_content_has_identifier_in_place():

FILE: knittingpattern/convert/test/test_instruction_to_svg.py
  function knit (line 12) | def knit():
  function purl (line 17) | def purl():
  function yo (line 22) | def yo():
  function its (line 27) | def its():
  function loaded (line 32) | def loaded(its):
  function default (line 38) | def default(its):
  class TestHasSVGForInstruction (line 43) | class TestHasSVGForInstruction(object):
    method test_load_from_file (line 46) | def test_load_from_file(self, its, knit):
    method test_nothing_is_loaded (line 50) | def test_nothing_is_loaded(self, its, knit, purl):
    method test_load_from_directory (line 54) | def test_load_from_directory(self, its, knit, purl):
    method test_all_images_are_loaded (line 59) | def test_all_images_are_loaded(self, loaded, knit, purl, yo):
    method test_default_returns_empty_string_if_nothing_is_loaded (line 64) | def test_default_returns_empty_string_if_nothing_is_loaded(self, its,
  class TestDefaultInstrucionToSVG (line 69) | class TestDefaultInstrucionToSVG(object):
    method test_instruction_type_is_replaced_in_default (line 72) | def test_instruction_type_is_replaced_in_default(self, default, knit):
    method test_default_instruction_is_used (line 75) | def test_default_instruction_is_used(self, default, purl):
  function is_color_layer (line 81) | def is_color_layer(layer):
  function color_layers (line 87) | def color_layers(svg):
  function assert_has_one_colored_layer (line 91) | def assert_has_one_colored_layer(svg):
  function assert_fill_has_color_of (line 95) | def assert_fill_has_color_of(svg, instruction):
  class TestInstructionToSVG (line 104) | class TestInstructionToSVG(object):
    method knit_svg (line 107) | def knit_svg(self, loaded, knit):
    method purl_svg (line 111) | def purl_svg(self, loaded, purl):
    method test_file_content_is_included (line 114) | def test_file_content_is_included(self, knit_svg):
    method test_file_content_is_purl (line 117) | def test_file_content_is_purl(self, purl_svg):
    method test_returned_object_is_svg_with_viewbox (line 120) | def test_returned_object_is_svg_with_viewbox(self, knit_svg):
    method test_there_is_one_color_layer (line 123) | def test_there_is_one_color_layer(self, knit_svg):
    method test_purl_has_one_color_layer (line 126) | def test_purl_has_one_color_layer(self, purl_svg):
    method test_fill_in_colored_layer_is_replaced_by_color (line 129) | def test_fill_in_colored_layer_is_replaced_by_color(self, knit_svg, kn...
    method test_purl_is_colored (line 132) | def test_purl_is_colored(self, purl_svg, purl):

FILE: knittingpattern/convert/test/test_knittingpattern_to_png.py
  function block4x4 (line 7) | def block4x4():
  function path (line 12) | def path(block4x4):
  function image (line 17) | def image(path):
  function test_there_is_a_green_line (line 22) | def test_there_is_a_green_line(image, xy):
  function test_path_ends_with_png (line 26) | def test_path_ends_with_png(path):

FILE: knittingpattern/convert/test/test_layout.py
  function coordinates (line 9) | def coordinates(layout):
  function sizes (line 14) | def sizes(layout):
  function instructions (line 19) | def instructions(layout):
  function row_ids (line 24) | def row_ids(layout):
  function connections (line 29) | def connections(layout):
  class BaseTest (line 34) | class BaseTest:
    method pattern (line 47) | def pattern(self):
    method grid (line 54) | def grid(self, pattern):
    method test_coordinates (line 58) | def test_coordinates(self, grid):
    method test_size (line 65) | def test_size(self, grid):
    method test_instructions (line 72) | def test_instructions(self, grid, pattern):
    method test_row_ids (line 80) | def test_row_ids(self, grid):
    method test_connections (line 84) | def test_connections(self, grid):
    method test_bounding_box (line 91) | def test_bounding_box(self, grid):
  class TestBlock4x4 (line 96) | class TestBlock4x4(BaseTest):
  class TestHole (line 100) | class TestHole(BaseTest):
  class TestAddAndRemoveMeshes (line 110) | class TestAddAndRemoveMeshes(BaseTest):
    method i_1 (line 125) | def i_1(self, pattern):
    method i_2 (line 129) | def i_2(self, pattern):
    method i_3 (line 133) | def i_3(self, pattern):
    method i_4 (line 137) | def i_4(self, pattern):
    method instructions (line 141) | def instructions(self, i_1, i_2, i_3, i_4):
    method test_all_consume_one_mesh (line 144) | def test_all_consume_one_mesh(self, instructions):
    method test_all_produce_one_mesh (line 148) | def test_all_produce_one_mesh(self, instructions):
    method test_i_1_0_is_not_produced (line 154) | def test_i_1_0_is_not_produced(self, i_1):
    method test_i_1_1_is_not_produced (line 157) | def test_i_1_1_is_not_produced(self, i_1):
    method test_i_1_2_is_not_produced (line 160) | def test_i_1_2_is_not_produced(self, i_1):
    method test_i_1_3_is_not_produced (line 163) | def test_i_1_3_is_not_produced(self, i_1):
    method test_i_1_0_consumed (line 168) | def test_i_1_0_consumed(self, i_1, i_2):
    method test_i_1_1_consumed (line 171) | def test_i_1_1_consumed(self, i_1, i_2):
    method test_i_1_2_consumed (line 174) | def test_i_1_2_consumed(self, i_1, i_2):
    method test_i_1_3_consumed (line 177) | def test_i_1_3_consumed(self, i_1, i_2):
    method test_i_2_0_produced (line 182) | def test_i_2_0_produced(self, i_1, i_2):
    method test_i_2_1_produced (line 185) | def test_i_2_1_produced(self, i_1, i_2):
    method test_i_2_2_produced (line 188) | def test_i_2_2_produced(self, i_1, i_2):
    method test_i_2_3_produced (line 191) | def test_i_2_3_produced(self, i_1, i_2):
    method test_i_2_4_produced (line 194) | def test_i_2_4_produced(self, i_2):
    method test_i_2_0_consumed (line 199) | def test_i_2_0_consumed(self, i_2, i_3):
    method test_i_2_1_consumed (line 202) | def test_i_2_1_consumed(self, i_2, i_3):
    method test_i_2_2_consumed (line 205) | def test_i_2_2_consumed(self, i_2, i_3):
    method test_i_2_3_not_consumed (line 208) | def test_i_2_3_not_consumed(self, i_2):
    method test_i_2_4_not_consumed (line 211) | def test_i_2_4_not_consumed(self, i_2):
    method test_i_3_0_produced (line 216) | def test_i_3_0_produced(self, i_2, i_3):
    method test_i_3_1_produced (line 219) | def test_i_3_1_produced(self, i_2, i_3):
    method test_i_3_2_produced (line 222) | def test_i_3_2_produced(self, i_2, i_3):
    method test_i_3_0_consumed (line 227) | def test_i_3_0_consumed(self, i_3, i_4):
    method test_i_3_1_consumed (line 230) | def test_i_3_1_consumed(self, i_3, i_4):
    method test_i_3_2_consumed (line 233) | def test_i_3_2_consumed(self, i_3, i_4):
    method test_i_4_0_not_produced (line 238) | def test_i_4_0_not_produced(self, i_4):
    method test_i_4_1_produced (line 241) | def test_i_4_1_produced(self, i_3, i_4):
    method test_i_4_2_produced (line 244) | def test_i_4_2_produced(self, i_3, i_4):
    method test_i_4_3_produced (line 247) | def test_i_4_3_produced(self, i_3, i_4):
    method test_i_4_4_not_produced (line 250) | def test_i_4_4_not_produced(self, i_4):
    method test_i_4_0_not_consumed (line 255) | def test_i_4_0_not_consumed(self, i_4):
    method test_i_4_1_not_consumed (line 258) | def test_i_4_1_not_consumed(self, i_4):
    method test_i_4_2_not_consumed (line 261) | def test_i_4_2_not_consumed(self, i_4):
    method test_i_4_3_not_consumed (line 264) | def test_i_4_3_not_consumed(self, i_4):
    method test_i_4_4_not_consumed (line 267) | def test_i_4_4_not_consumed(self, i_4):
  class TestParallelRows (line 271) | class TestParallelRows(BaseTest):
    method row_4 (line 289) | def row_4(self, pattern):
    method skp (line 293) | def skp(self, row_4):
    method test_skp_has_2_consumed_meshes (line 296) | def test_skp_has_2_consumed_meshes(self, skp):
    method test_row_4_1_consumes_5_meshes (line 301) | def test_row_4_1_consumes_5_meshes(self, row_4):
  function test_get_color_from_instruction_in_grid (line 309) | def test_get_color_from_instruction_in_grid():
  class TestSmallCafe (line 316) | class TestSmallCafe(BaseTest):
  class TestCastOffAndBindOn (line 342) | class TestCastOffAndBindOn(BaseTest):
    method cast_on (line 352) | def cast_on(self, co_row):
    method co_row (line 356) | def co_row(self, pattern):
    method co_row_in_grid (line 360) | def co_row_in_grid(self, grid, co_row):
    method test_cast_on_has_layout_specific_width (line 363) | def test_cast_on_has_layout_specific_width(self, cast_on):
    method test_first_row_has_width_4 (line 367) | def test_first_row_has_width_4(self, co_row_in_grid):

FILE: knittingpattern/convert/test/test_png_to_knittingpattern.py
  function patterns (line 12) | def patterns(image_path, convert):
  function pattern (line 18) | def pattern(patterns):
  function image (line 23) | def image(image_path):
  function pytest_generate_tests (line 27) | def pytest_generate_tests(metafunc):
  function test_convert_image_to_knittingpattern (line 38) | def test_convert_image_to_knittingpattern(patterns, image_path):
  function test_row_length_is_image_length (line 42) | def test_row_length_is_image_length(pattern, image):
  function test_first_color_is_white (line 47) | def test_first_color_is_white(pattern):
  function test_other_color_is_white (line 51) | def test_other_color_is_white(pattern):
  function test_black_exists (line 55) | def test_black_exists(pattern):
  function test_order_of_conversion (line 59) | def test_order_of_conversion():

FILE: knittingpattern/convert/test/test_save_as_svg.py
  function is_close_to (line 14) | def is_close_to(v1, v2, relative_epsilon=0.01):
  function patterns_svg (line 19) | def patterns_svg():
  function path (line 24) | def path(patterns_svg):
  function svg (line 29) | def svg(path):
  function rows (line 34) | def rows(svg):
  function instructions (line 39) | def instructions(rows):
  function rows_test (line 43) | def rows_test(function):
  function instructions_test (line 50) | def instructions_test(function):
  function instructions_svg_test (line 57) | def instructions_svg_test(function):
  function test_svg_contains_four_rows (line 64) | def test_svg_contains_four_rows(svg):
  function test_rows_contain_four_instructions (line 69) | def test_rows_contain_four_instructions(row_id, row):
  function test_rows_are_labeled_for_inkscape (line 74) | def test_rows_are_labeled_for_inkscape(row_id, row):
  function test_row_is_inkscape_layer (line 79) | def test_row_is_inkscape_layer(row_id, row):
  function test_rows_have_class_for_styling (line 84) | def test_rows_have_class_for_styling(row_id, row):
  function test_rows_have_id_for_styling (line 89) | def test_rows_have_id_for_styling(row_id, row):
  function test_instructions_have_class (line 94) | def test_instructions_have_class(instruction):
  function test_instructions_have_id (line 99) | def test_instructions_have_id(instruction):
  function test_instructions_content_is_knit_svg_file (line 105) | def test_instructions_content_is_knit_svg_file(instruction):
  function test_instructions_have_transform (line 110) | def test_instructions_have_transform(instruction, svg, path, patterns_svg):

FILE: knittingpattern/test/test_add_and_remove_instructions.py
  function single_instruction_pattern_set (line 8) | def single_instruction_pattern_set():
  function pattern (line 14) | def pattern(single_instruction_pattern_set):
  function row (line 20) | def row(pattern):
  function row2 (line 26) | def row2(pattern):
  function instruction (line 32) | def instruction(row):
  function instruction2 (line 38) | def instruction2(row2):
  function empty_row (line 44) | def empty_row(row, instruction):
  function test_there_is_only_one_instruction (line 51) | def test_there_is_only_one_instruction(row):
  function test_removing_the_instruction_gives_an_error_when_accessing_its_index (line 59) | def test_removing_the_instruction_gives_an_error_when_accessing_its_index(
  function test_inserting_a_new_instruction_loads_its_config (line 68) | def test_inserting_a_new_instruction_loads_its_config(row):
  function test_insert_an_existing_instruction (line 77) | def test_insert_an_existing_instruction(row, instruction2, row2):
  function test_transfer_removed_instruction (line 84) | def test_transfer_removed_instruction(row, row2):

FILE: knittingpattern/test/test_change_row_mapping.py
  function patterns (line 7) | def patterns():
  function line (line 12) | def line(patterns):
  function row1 (line 17) | def row1(line):
  function row2 (line 22) | def row2(line):
  function row3 (line 27) | def row3(line):
  function mesh11p (line 34) | def mesh11p(row1):
  function mesh12p (line 39) | def mesh12p(row1):
  function mesh21p (line 44) | def mesh21p(row2):
  function mesh31p (line 49) | def mesh31p(row3):
  function mesh11c (line 56) | def mesh11c(row1):
  function mesh12c (line 61) | def mesh12c(row1):
  function mesh21c (line 66) | def mesh21c(row2):
  function mesh31c (line 71) | def mesh31c(row3):
  function connected_meshes (line 76) | def connected_meshes(mesh11p, mesh21c, mesh21p, mesh31c):
  function disconnected_meshes (line 81) | def disconnected_meshes(mesh11c, mesh12c, mesh12p, mesh31p):
  function meshes (line 86) | def meshes(connected_meshes, disconnected_meshes):
  function connections (line 91) | def connections(mesh11p, mesh21c, mesh21p, mesh31c):
  function two_way_connections (line 96) | def two_way_connections(mesh11p, mesh21c, mesh21p, mesh31c):
  function produced_meshes (line 102) | def produced_meshes(mesh11p, mesh12p, mesh21p, mesh31p):
  function consumed_meshes (line 107) | def consumed_meshes(mesh11c, mesh12c, mesh21c, mesh31c):
  function pytest_generate_tests (line 111) | def pytest_generate_tests(metafunc):
  function connect_meshes (line 118) | def connect_meshes(mesh1, mesh2, connect):
  function disconnect_meshes (line 124) | def disconnect_meshes(mesh1, mesh2, disconnect):
  class TestLine (line 129) | class TestLine(object):
    method test_consumed_meshes_of_row1 (line 133) | def test_consumed_meshes_of_row1(self, row1, mesh11c, mesh12c):
    method test_produced_meshes_of_row1 (line 139) | def test_produced_meshes_of_row1(self, row1, mesh11p, mesh12p):
    method test_consumed_mesh_of_row2 (line 146) | def test_consumed_mesh_of_row2(self, row2, mesh21c):
    method test_produced_mesh_of_row2 (line 151) | def test_produced_mesh_of_row2(self, row2, mesh21p):
    method test_consumed_mesh_of_row3 (line 156) | def test_consumed_mesh_of_row3(self, row3, mesh31c):
    method test_produced_mesh_of_row3 (line 161) | def test_produced_mesh_of_row3(self, row3, mesh31p):
    method test_is_connected (line 166) | def test_is_connected(self, connected_meshes):
    method test_is_disconnected (line 170) | def test_is_disconnected(self, disconnected_meshes):
    method test_equality (line 177) | def test_equality(self, connections):
    method test_is_connected_to (line 182) | def test_is_connected_to(self, two_way_connections):
    method test_disconnected_from (line 186) | def test_disconnected_from(self, connections, meshes):
    method test_as_produced_mesh (line 201) | def test_as_produced_mesh(self, produced_meshes):
    method test_as_consumed_mesh (line 205) | def test_as_consumed_mesh(self, consumed_meshes):
  function test_remove_a_connection (line 210) | def test_remove_a_connection(row1, row2, mesh11p, mesh21c, disconnect):
  function test_replace_a_connection (line 227) | def test_replace_a_connection(disconnect, connect, mesh21p, mesh31c, mes...
  function test_connect_to_a_connected_location (line 248) | def test_connect_to_a_connected_location(mesh12p, mesh31c, mesh21p, conn...
  function test_connect_to_a_connected_location_with_connected_mesh (line 256) | def test_connect_to_a_connected_location_with_connected_mesh(
  function test_can_connect (line 264) | def test_can_connect(connected_meshes, consumed_meshes, produced_meshes):
  function test_create_new_connection (line 272) | def test_create_new_connection(mesh31p, mesh12c, connect, row1, row3):
  function test_disconnect_disconnected (line 285) | def test_disconnect_disconnected(mesh12c):

FILE: knittingpattern/test/test_default_instructions.py
  function default (line 21) | def default():
  function test_mesh_consumption (line 26) | def test_mesh_consumption(default, type_, value):
  function test_mesh_production (line 31) | def test_mesh_production(default, type_, value):
  function test_description_present (line 36) | def test_description_present(default, type_):
  function test_all_default_instructions_are_tested (line 42) | def test_all_default_instructions_are_tested(default):
  function test_default_instructions_is_a_singleton (line 48) | def test_default_instructions_is_a_singleton():
  function test_default_instructions_are_an_instance_of_the_class (line 52) | def test_default_instructions_are_an_instance_of_the_class():

FILE: knittingpattern/test/test_dump_json.py
  function obj (line 9) | def obj():
  function dumper (line 14) | def dumper(obj):
  function parser (line 21) | def parser():
  function test_dump_object (line 25) | def test_dump_object(dumper, obj):
  function test_dump_string (line 29) | def test_dump_string(dumper, obj):
  function test_dump_to_temporary_file (line 33) | def test_dump_to_temporary_file(dumper, obj):
  function test_dump_to_knitting_pattern (line 40) | def test_dump_to_knitting_pattern(dumper, parser, obj):
  function test_string_representation (line 47) | def test_string_representation(dumper):

FILE: knittingpattern/test/test_dumper.py
  function unicode (line 12) | def unicode():
  function binary (line 20) | def binary():
  function no_encode_text (line 28) | def no_encode_text():
  function no_encode_binary (line 33) | def no_encode_binary():
  function pytest_generate_tests (line 39) | def pytest_generate_tests(metafunc):
  function temp_file (line 45) | def temp_file(save_to):
  function binary_temp_file (line 50) | def binary_temp_file(save_to):
  function stringio (line 55) | def stringio():
  function assert_string_is_file_content (line 59) | def assert_string_is_file_content(file):
  function assert_string_is_path_content (line 64) | def assert_string_is_path_content(path):
  function assert_string_is_binary_content (line 69) | def assert_string_is_binary_content(file):
  function test_string_is_long (line 74) | def test_string_is_long():
  function test_dump_to_string (line 78) | def test_dump_to_string(save_to):
  function test_dump_to_file (line 82) | def test_dump_to_file(save_to, stringio):
  function test_dump_is_behind_content_in_file (line 87) | def test_dump_is_behind_content_in_file(save_to, stringio):
  function test_dump_to_path (line 92) | def test_dump_to_path(save_to, tmpdir):
  function test_dump_to_temp_path (line 98) | def test_dump_to_temp_path(save_to):
  function test_dump_to_temporary_file (line 103) | def test_dump_to_temporary_file(temp_file):
  function test_dump_to_temporary_binary_file (line 107) | def test_dump_to_temporary_binary_file(binary_temp_file):
  function test_temporary_file_is_deleted_on_default (line 111) | def test_temporary_file_is_deleted_on_default(temp_file):
  function test_binary_temporary_file_is_deleted_on_default (line 115) | def test_binary_temporary_file_is_deleted_on_default(binary_temp_file):
  function assert_temporary_file_is_deleted (line 119) | def assert_temporary_file_is_deleted(temp_file):
  function assert_temporary_file_is_not_deleted (line 124) | def assert_temporary_file_is_not_deleted(temp_file):
  function test_temporary_file_exists (line 129) | def test_temporary_file_exists(temp_file):
  function test_binary_temporary_file_exists (line 133) | def test_binary_temporary_file_exists(binary_temp_file):
  function test_temporary_file_has_option_for_deletion (line 137) | def test_temporary_file_has_option_for_deletion(save_to):
  function test_binary_temporary_file_has_option_for_deletion (line 142) | def test_binary_temporary_file_has_option_for_deletion(save_to):
  function test_file_returns_new_file (line 147) | def test_file_returns_new_file(save_to):
  function test_dump_is_behind_content_in_new_file (line 152) | def test_dump_is_behind_content_in_new_file(save_to, stringio):
  function test_bytes (line 157) | def test_bytes(save_to):
  function test_encoding (line 161) | def test_encoding(save_to):
  function test_new_binary_file (line 165) | def test_new_binary_file(save_to):
  function test_binary_file (line 171) | def test_binary_file(save_to):
  function test_test_binary_file_is_at_end (line 178) | def test_test_binary_file_is_at_end(save_to):
  function test_encoding_is_none (line 182) | def test_encoding_is_none(no_encode_binary, no_encode_text):
  function test_temporary_path_has_extension (line 187) | def test_temporary_path_has_extension(save_to):
  function test_string_representation (line 192) | def test_string_representation(save_to):

FILE: knittingpattern/test/test_example_code.py
  function test_load_from_example_and_create_svg (line 4) | def test_load_from_example_and_create_svg():

FILE: knittingpattern/test/test_example_rows.py
  function charlotte (line 7) | def charlotte():
  function a1 (line 12) | def a1(charlotte):
  function a2 (line 18) | def a2(charlotte):
  function test_number_of_rows (line 23) | def test_number_of_rows(a1):
  function test_row_ids (line 30) | def test_row_ids(a1):
  function test_access_by_row_ids (line 36) | def test_access_by_row_ids(a1):
  function test_iterate_on_rows (line 41) | def test_iterate_on_rows(a1):

FILE: knittingpattern/test/test_examples.py
  function charlotte (line 13) | def charlotte():
  function cafe (line 18) | def cafe():
  function test_number_of_patterns (line 22) | def test_number_of_patterns(charlotte):
  function pattern_0 (line 29) | def pattern_0(charlotte):
  function pattern_1 (line 34) | def pattern_1(charlotte):
  function test_names (line 38) | def test_names(pattern_0, pattern_1):
  function test_ids (line 43) | def test_ids(pattern_0, pattern_1):
  function test_access_with_id (line 48) | def test_access_with_id(charlotte):
  function test_iterate_on_pattern (line 52) | def test_iterate_on_pattern(charlotte):

FILE: knittingpattern/test/test_id_collection.py
  function c (line 10) | def c():
  function test_no_object (line 14) | def test_no_object(c):
  function test_add_object (line 19) | def test_add_object(c):
  function test_length (line 28) | def test_length(c):
  function test_at_raises_keyerror (line 36) | def test_at_raises_keyerror(c):

FILE: knittingpattern/test/test_instruction.py
  function default_instruction (line 7) | def default_instruction():
  function purl (line 12) | def purl():
  function yo (line 17) | def yo():
  function bindoff (line 22) | def bindoff():
  function colored_instruction (line 27) | def colored_instruction():
  function test_default_type (line 39) | def test_default_type(default_instruction):
  function test_default_color (line 45) | def test_default_color(default_instruction):
  function test_width (line 50) | def test_width(default_instruction, purl):
  function test_purl_is_not_knit (line 57) | def test_purl_is_not_knit(purl):
  function test_color (line 62) | def test_color(colored_instruction):
  function test_inheritance (line 68) | def test_inheritance(colored_instruction):
  function test_purl_produces_meshes (line 74) | def test_purl_produces_meshes(purl):
  function test_purl_consumes_meshes (line 78) | def test_purl_consumes_meshes(purl):
  function test_yarn_over_consumes_no_meshes (line 82) | def test_yarn_over_consumes_no_meshes(yo):
  function test_yarn_over_produces_meshes (line 87) | def test_yarn_over_produces_meshes(yo):
  function test_bindoff_consumes_meshes (line 92) | def test_bindoff_consumes_meshes(bindoff):
  function test_bindoff_produces_no_meshes (line 97) | def test_bindoff_produces_no_meshes(bindoff):
  class TestInstructionColors (line 102) | class TestInstructionColors(object):
    method test_get_colors_from_color_specification (line 108) | def test_get_colors_from_color_specification(self, spec, colors):

FILE: knittingpattern/test/test_instruction_library.py
  function library (line 27) | def library():
  function library2 (line 32) | def library2(library):
  function knit (line 42) | def knit(library):
  function purl (line 47) | def purl(library):
  function custom_knit (line 52) | def custom_knit(library):
  function test_knit_type_attributes (line 56) | def test_knit_type_attributes(knit):
  function test_knit_has_no_color (line 62) | def test_knit_has_no_color(knit):
  function test_purl_has_color (line 67) | def test_purl_has_color(purl):
  function test_not_everyting_is_known_by_purl (line 72) | def test_not_everyting_is_known_by_purl(purl):
  function test_custom_type (line 78) | def test_custom_type(custom_knit):
  function test_default_instruction_is_knit (line 82) | def test_default_instruction_is_knit(library):
  function test_library_does_not_forget_old_values (line 86) | def test_library_does_not_forget_old_values(library2):
  function test_library_can_load_multiple_times (line 90) | def test_library_can_load_multiple_times(library2):
  function test_library_handles_loading_several_instructions_with_same_type (line 94) | def test_library_handles_loading_several_instructions_with_same_type(lib...
  function test_access_via_type (line 98) | def test_access_via_type(library):
  function test_when_library_load_instruction_it_is_in_its_types (line 104) | def test_when_library_load_instruction_it_is_in_its_types(library2):
  function test_unloaded_instruction_is_not_in_the_types (line 109) | def test_unloaded_instruction_is_not_in_the_types(library2):

FILE: knittingpattern/test/test_instruction_row_inheritance.py
  function coloring_pattern (line 8) | def coloring_pattern():
  function test_instruction_has_color (line 30) | def test_instruction_has_color(coloring_pattern, row_id,
  function test_rows_have_color (line 47) | def test_rows_have_color(coloring_pattern, row_id, color):

FILE: knittingpattern/test/test_knittingpattern.py
  class TestInstructionColors (line 10) | class TestInstructionColors(object):
    method unique (line 15) | def unique(self, monkeypatch):
    method rows_in_knit_order (line 21) | def rows_in_knit_order(self, rows, monkeypatch):
    method rows (line 28) | def rows(self):
    method knittingpattern (line 32) | def knittingpattern(self, rows):
    method test_result (line 35) | def test_result(self, knittingpattern, unique, rows_in_knit_order):
    method test_call_arguments (line 38) | def test_call_arguments(self, knittingpattern, unique, rows,
    method test_chalotte (line 44) | def test_chalotte(self, a1):
    method test_cafe (line 47) | def test_cafe(self):

FILE: knittingpattern/test/test_load_instructions.py
  function lib (line 7) | def lib():
  function test_load_from_relative_file (line 11) | def test_load_from_relative_file(lib):
  function test_load_from_relative_folder (line 18) | def test_load_from_relative_folder(lib):
  function test_load_from_folder (line 24) | def test_load_from_folder(lib):
  function test_loading_from_folder_recursively (line 31) | def test_loading_from_folder_recursively(lib):

FILE: knittingpattern/test/test_loader.py
  function result (line 10) | def result():
  function loader (line 15) | def loader(result):
  function path_loader (line 28) | def path_loader():
  function jsonloader (line 33) | def jsonloader(result):
  function test_loading_object_does_nothing (line 37) | def test_loading_object_does_nothing(loader, result):
  function test_processing_result_is_returned (line 43) | def test_processing_result_is_returned(loader):
  function test_json_loader_loads_json (line 48) | def test_json_loader_loads_json(jsonloader, result):
  function test_loader_would_like_to_load_path (line 53) | def test_loader_would_like_to_load_path(loader):
  function test_loader_does_not_like_certain_paths (line 57) | def test_loader_does_not_like_certain_paths(loader):
  function test_loader_can_select_paths_it_likes (line 61) | def test_loader_can_select_paths_it_likes(loader):
  function test_loading_from_directory_selects_paths (line 66) | def test_loading_from_directory_selects_paths(loader):
  function example_path (line 74) | def example_path(example):
  function test_load_example (line 79) | def test_load_example(path_loader, example):
  function test_load_examples (line 85) | def test_load_examples(path_loader):

FILE: knittingpattern/test/test_parsing.py
  function temp_empty_pattern_path (line 12) | def temp_empty_pattern_path(tmpdir):
  function assert_is_pattern (line 19) | def assert_is_pattern(pattern):
  function test_can_import_empty_pattern_from_object (line 24) | def test_can_import_empty_pattern_from_object():
  function test_can_import_empty_pattern_from_string (line 29) | def test_can_import_empty_pattern_from_string():
  function test_can_import_empty_pattern_from_file_object (line 35) | def test_can_import_empty_pattern_from_file_object(temp_empty_pattern_pa...
  function test_can_import_empty_pattern_from_path (line 41) | def test_can_import_empty_pattern_from_path(temp_empty_pattern_path):
  function test_knitting_pattern_type_is_present (line 46) | def test_knitting_pattern_type_is_present():
  function test_knitting_pattern_type_is_correct (line 51) | def test_knitting_pattern_type_is_correct():
  function test_load_from_url (line 56) | def test_load_from_url(temp_empty_pattern_path):

FILE: knittingpattern/test/test_row_instructions.py
  function a1 (line 12) | def a1():
  function row0 (line 18) | def row0(a1):
  function row1 (line 23) | def row1(a1):
  function row2 (line 28) | def row2(a1):
  function mesh0 (line 33) | def mesh0(row0):
  function instruction0 (line 39) | def instruction0(row0):
  function instruction1 (line 44) | def instruction1(row1):
  function removed_instruction (line 49) | def removed_instruction(row0):
  function test_row0_consumes_empty_meshes (line 53) | def test_row0_consumes_empty_meshes(row0):
  function test_consumed_meshes_have_index (line 58) | def test_consumed_meshes_have_index(row0):
  function test_row0_produces_5_meshes (line 65) | def test_row0_produces_5_meshes(row0):
  function test_row0_meshes_point_also_to_row1 (line 70) | def test_row0_meshes_point_also_to_row1(mesh0, row0, row1):
  function test_row0_instruction_produces_mesh_0 (line 75) | def test_row0_instruction_produces_mesh_0(mesh0, instruction0):
  function test_instruction0_is_knit (line 81) | def test_instruction0_is_knit(instruction0):
  function test_instruction_position_in_row (line 85) | def test_instruction_position_in_row(row0, instruction0):
  function test_mesh0_is_consumed_by_instruction1 (line 91) | def test_mesh0_is_consumed_by_instruction1(mesh0, instruction1):
  function test_instruction1_is_knit (line 96) | def test_instruction1_is_knit(instruction1):
  function test_instruction1_position_in_row (line 100) | def test_instruction1_position_in_row(instruction1):
  function test_mesh0_is_produced (line 104) | def test_mesh0_is_produced(mesh0):
  function test_instruction0_builds_on_unproduced_meshes (line 109) | def test_instruction0_builds_on_unproduced_meshes(instruction0):
  function skp (line 114) | def skp(row2):
  function yo (line 119) | def yo(row2):
  function test_yarn_over (line 123) | def test_yarn_over(yo):
  function test_skp (line 128) | def test_skp(skp):
  function test_position_in_row2 (line 133) | def test_position_in_row2(skp, yo, row2):
  function test_skp_consumed_meshes_from_row1 (line 140) | def test_skp_consumed_meshes_from_row1(skp, row1, row2):
  function test_skp_produces_one_mesh (line 157) | def test_skp_produces_one_mesh(skp):
  function test_skp_produced_meshes (line 161) | def test_skp_produced_meshes(skp, row2):
  function test_yarn_over_consumes_no_meshes (line 170) | def test_yarn_over_consumes_no_meshes(yo):
  function test_yarn_over_produces_a_mesh (line 174) | def test_yarn_over_produces_a_mesh(yo):
  function test_previous_instruction (line 182) | def test_previous_instruction(row0, instruction0):
  function test_next_instruction (line 186) | def test_next_instruction(row0, instruction0):
  function test_previous_instruction_is_None_at_border (line 190) | def test_previous_instruction_is_None_at_border(instruction0):
  function test_next_instruction_is_None_at_border (line 194) | def test_next_instruction_is_None_at_border(row0):
  function test_index_of_instruction_does_not_change (line 198) | def test_index_of_instruction_does_not_change(instruction0):
  function test_repr (line 204) | def test_repr(instruction0):
  function test_instruction_consumes_no_mesh_but_has_mesh_index (line 211) | def test_instruction_consumes_no_mesh_but_has_mesh_index(yo):
  function test_index_of_last_produced_mesh_is_same_as_first (line 216) | def test_index_of_last_produced_mesh_is_same_as_first(yo):
  function test_removed_instruction_raises_exception (line 222) | def test_removed_instruction_raises_exception(removed_instruction):
  function test_instruction_is_in_row (line 233) | def test_instruction_is_in_row(instruction0):
  function test_instruction_is_not_in_row (line 237) | def test_instruction_is_not_in_row(removed_instruction):
  function test_repr_removed_instruction (line 241) | def test_repr_removed_instruction(removed_instruction):
  function test_repr_meshes (line 245) | def test_repr_meshes(instruction0, row2):
  class TestShortAccess (line 251) | class TestShortAccess(object):
    method test_first_instruction (line 255) | def test_first_instruction(self, a1):
    method test_last_instruction (line 259) | def test_last_instruction(self, a1):
  class TestInstructionColors (line 264) | class TestInstructionColors(object):
    method test_row_instructions (line 273) | def test_row_instructions(self, specs, result, row_spec, default_color):

FILE: knittingpattern/test/test_row_mapping.py
  function p1 (line 11) | def p1():
  function a1 (line 16) | def a1(p1):
  function r11 (line 21) | def r11(a1):
  function r21 (line 26) | def r21(a1):
  function r22 (line 31) | def r22(a1):
  function r32 (line 36) | def r32(a1):
  function r41 (line 41) | def r41(a1):
  function assert_rows_map (line 47) | def assert_rows_map(row1, index1, row2, index2):
  function assert_is_not_connected (line 53) | def assert_is_not_connected(row, index):
  class TestRow11 (line 57) | class TestRow11:
    method test_first_meshes_map_to_second_row (line 59) | def test_first_meshes_map_to_second_row(self, r11, r21):
    method test_middle_mesh_does_not_map_to_any_row (line 63) | def test_middle_mesh_does_not_map_to_any_row(self, r11):
    method test_right_meshes_map_to_third_row (line 66) | def test_right_meshes_map_to_third_row(self, r11, r22):
    method test_number_of_meshes (line 70) | def test_number_of_meshes(self, r11):
  class TestRow21 (line 75) | class TestRow21:
    method test_all_meshes_map_to_last_row (line 77) | def test_all_meshes_map_to_last_row(self, r21, r41):
    method test_number_of_meshes (line 81) | def test_number_of_meshes(self, r21):
  class TestRow22 (line 86) | class TestRow22:
    method test_all_meshes_map_to_row_3 (line 88) | def test_all_meshes_map_to_row_3(self, r22, r32):
  class TestRow32 (line 93) | class TestRow32:
    method test_all_meshes_map_to_last_row (line 95) | def test_all_meshes_map_to_last_row(self, r32, r41):
  class TestRow41 (line 100) | class TestRow41:
    method test_row_maps_to_nowhere (line 102) | def test_row_maps_to_nowhere(self, r41):
    method test_number_of_meshes (line 106) | def test_number_of_meshes(self, r41):

FILE: knittingpattern/test/test_row_meshes.py
  function assert_consumed_index (line 10) | def assert_consumed_index(mesh, instruction_index, index_in_instruction=0):
  function assert_produced_index (line 15) | def assert_produced_index(mesh, instruction_index, index_in_instruction=0):
  function assert_row (line 20) | def assert_row(row, first_consumed, last_consumed, first_produced,
  function row (line 29) | def row():
  function test_no_meshes (line 34) | def test_no_meshes(row):
  function test_knit_row (line 45) | def test_knit_row(row):
  function test_1_or_0 (line 50) | def test_1_or_0(row):
  function test_2 (line 55) | def test_2(row):
  function test_2_reversed (line 60) | def test_2_reversed(row):

FILE: knittingpattern/test/test_utilities.py
  class TestUniquenes (line 5) | class TestUniquenes(object):
    method test_results (line 14) | def test_results(self, input, expected_result, use_generator):

FILE: knittingpattern/test/test_walk.py
  function walk_ids (line 7) | def walk_ids(pattern):
  function test_test_patterns (line 18) | def test_test_patterns(pattern_file, expected_ids):
  function construct_graph (line 25) | def construct_graph(links):
  function test_graphs_are_sorted (line 49) | def test_graphs_are_sorted(links, expected_ids):

FILE: knittingpattern/utils.py
  function unique (line 8) | def unique(iterables):

FILE: knittingpattern/walk.py
  function walk (line 4) | def walk(knitting_pattern):

FILE: setup.py
  function read_file_named (line 22) | def read_file_named(file_name):
  function read_requirements_file (line 28) | def read_requirements_file(file_name):
  class TestCommand (line 58) | class TestCommand(TestCommandBase):
    method finalize_options (line 62) | def finalize_options(self):
    method run_tests (line 66) | def run_tests(self):
  class CoverageTestCommand (line 72) | class CoverageTestCommand(TestCommand):
  class PEP8TestCommand (line 76) | class PEP8TestCommand(TestCommand):
  class FlakesTestCommand (line 80) | class FlakesTestCommand(TestCommand):
  class CoveragePEP8TestCommand (line 84) | class CoveragePEP8TestCommand(TestCommand):
  class LintCommand (line 88) | class LintCommand(TestCommandBase):
    method finalize_options (line 92) | def finalize_options(self):
    method run_tests (line 96) | def run_tests(self):
  class LinkIntoSitePackagesCommand (line 104) | class LinkIntoSitePackagesCommand(Command):
    method initialize_options (line 112) | def initialize_options(self):
    method finalize_options (line 115) | def finalize_options(self):
    method run (line 118) | def run(self):
    method run_linux_link (line 137) | def run_linux_link(self):
    method run_windows_link (line 143) | def run_windows_link(self):
  class PrintRequiredPackagesCommand (line 158) | class PrintRequiredPackagesCommand(Command):
    method initialize_options (line 165) | def initialize_options(self):
    method finalize_options (line 168) | def finalize_options(self):
    method run (line 172) | def run():
  class TagAndDeployCommand (line 200) | class TagAndDeployCommand(Command):
    method initialize_options (line 209) | def initialize_options(self):
    method finalize_options (line 212) | def finalize_options(self):
    method run (line 215) | def run(self):
  function main (line 283) | def main():
Condensed preview — 162 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (402K chars).
[
  {
    "path": ".codeclimate.yml",
    "chars": 242,
    "preview": "engines:\n  duplication:\n    enabled: true\n    config:\n      languages:\n      - python\n  fixme:\n    enabled: true\n  radon"
  },
  {
    "path": ".gitignore",
    "chars": 84,
    "preview": "/.cache\n/*.egg-info\n/*.__pycache__\n/dist\n/build\n*.pyc\n*.coverage\n/.eggs\n*.swp\n/.idea"
  },
  {
    "path": ".landscape.yaml",
    "chars": 183,
    "preview": "# https://docs.landscape.io/configuration.html\nstrictness: veryhigh\npython-targets:\n  - 3\npep8:\n    full: true\ndoc-warni"
  },
  {
    "path": ".travis.yml",
    "chars": 2541,
    "preview": "language: python\ncache: pip\nsudo: required\npython:\n- '3.3'\n- '3.4'\n- '3.5'\ninstall:\n# install the package\n- PACKAGE_VERS"
  },
  {
    "path": "CONTRIBUTING.rst",
    "chars": 133,
    "preview": "How to Contribute\n=================\n\n1. Read and agree to the `Developer Certificate of Origin\n<DeveloperCertificateOfOr"
  },
  {
    "path": "DeveloperCertificateOfOrigin.txt",
    "chars": 1422,
    "preview": "Developer Certificate of Origin\nVersion 1.1\n\nCopyright (C) 2004, 2006 The Linux Foundation and its contributors.\n660 Yor"
  },
  {
    "path": "LICENSE",
    "chars": 7401,
    "preview": "GNU LESSER GENERAL PUBLIC LICENSE\n\nVersion 3, 29 June 2007\n\nCopyright © 2007 Free Software Foundation, Inc. <http://fsf."
  },
  {
    "path": "MANIFEST.in",
    "chars": 141,
    "preview": "recursive-include knittingpattern *.py *.json *.svg\ninclude *requirements.txt\ninclude LICENSE\ninclude knittingpattern/co"
  },
  {
    "path": "README.rst",
    "chars": 2080,
    "preview": "Knitting Pattern Library\n===============\n\nThe knitting pattern library enables tailors, artisans and home knitters to us"
  },
  {
    "path": "appveyor.yml",
    "chars": 3155,
    "preview": "# see https://packaging.python.org/appveyor/#adding-appveyor-support-to-your-project\nclone_depth: 1\nenvironment:\n\n  PYPI"
  },
  {
    "path": "dev-requirements.in",
    "chars": 39,
    "preview": "pip-tools\nSphinx-PyPI-upload3\nautopep8\n"
  },
  {
    "path": "dev-requirements.txt",
    "chars": 367,
    "preview": "#\n# This file is autogenerated by pip-compile\n# To update, run:\n#\n#    pip-compile --output-file dev-requirements.txt de"
  },
  {
    "path": "docs/DevelopmentSetup.rst",
    "chars": 5019,
    "preview": ".. _development-setup:\n\nDevelopment Setup\n=================\n\nMake sure that you have the :ref:`repository installed\n<ins"
  },
  {
    "path": "docs/FileFormatSpecification.rst",
    "chars": 1062,
    "preview": ".. _FileFormatSpecification:\n\nKnitting Pattern File Format Specification\n==========================================\n\nFor"
  },
  {
    "path": "docs/Installation.rst",
    "chars": 1838,
    "preview": ".. _installation:\n\nknittingpattern Installation Instructions\n=========================================\n\nPackage installa"
  },
  {
    "path": "docs/Makefile",
    "chars": 7678,
    "preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD "
  },
  {
    "path": "docs/_static/.gitignore",
    "chars": 50,
    "preview": "# This file is used so the folder turns up in git."
  },
  {
    "path": "docs/_templates/.gitignore",
    "chars": 50,
    "preview": "# This file is used so the folder turns up in git."
  },
  {
    "path": "docs/conf.py",
    "chars": 12936,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n#\n# knittingpattern documentation build configuration file, created by\n# "
  },
  {
    "path": "docs/index.rst",
    "chars": 532,
    "preview": ".. knittingpattern documentation master file, created by\n   sphinx-quickstart on Thu Jun 23 09:49:51 2016.\n   You can ad"
  },
  {
    "path": "docs/make.bat",
    "chars": 7499,
    "preview": "@ECHO OFF\n\nREM Command file for Sphinx documentation\n\nset DOCDIR=.\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-b"
  },
  {
    "path": "docs/make_html.bat",
    "chars": 292,
    "preview": "@echo off\n\nREM \nREM This is a shortcut for notepad++\nREM You can press F5 and use this as command to update the html of "
  },
  {
    "path": "docs/reference/index.rst",
    "chars": 141,
    "preview": "Reference\n=========\n\n.. toctree::\n   :maxdepth: 2\n\n   knittingpattern/index\n   knittingpattern/convert/index\n   knitting"
  },
  {
    "path": "docs/reference/knittingpattern/Dumper/FileWrapper.rst",
    "chars": 226,
    "preview": "\n.. py:currentmodule:: knittingpattern.Dumper.FileWrapper\n\n:py:mod:`FileWrapper` Module\n============================\n\n.."
  },
  {
    "path": "docs/reference/knittingpattern/Dumper/file.rst",
    "chars": 198,
    "preview": "\n.. py:currentmodule:: knittingpattern.Dumper.file\n\n:py:mod:`file` Module\n=====================\n\n.. automodule:: knittin"
  },
  {
    "path": "docs/reference/knittingpattern/Dumper/index.rst",
    "chars": 183,
    "preview": "The ``knittingpattern.Dumper`` Module Reference\n===============================================\n\n.. toctree::\n   :maxdep"
  },
  {
    "path": "docs/reference/knittingpattern/Dumper/init.rst",
    "chars": 192,
    "preview": "\n.. py:currentmodule:: knittingpattern.Dumper\n\n:py:mod:`Dumper` Module\n=======================\n\n.. automodule:: knitting"
  },
  {
    "path": "docs/reference/knittingpattern/Dumper/json.rst",
    "chars": 198,
    "preview": "\n.. py:currentmodule:: knittingpattern.Dumper.json\n\n:py:mod:`json` Module\n=====================\n\n.. automodule:: knittin"
  },
  {
    "path": "docs/reference/knittingpattern/Dumper/svg.rst",
    "chars": 194,
    "preview": "\n.. py:currentmodule:: knittingpattern.Dumper.svg\n\n:py:mod:`svg` Module\n====================\n\n.. automodule:: knittingpa"
  },
  {
    "path": "docs/reference/knittingpattern/Dumper/xml.rst",
    "chars": 194,
    "preview": "\n.. py:currentmodule:: knittingpattern.Dumper.xml\n\n:py:mod:`xml` Module\n====================\n\n.. automodule:: knittingpa"
  },
  {
    "path": "docs/reference/knittingpattern/IdCollection.rst",
    "chars": 216,
    "preview": "\n.. py:currentmodule:: knittingpattern.IdCollection\n\n:py:mod:`IdCollection` Module\n=============================\n\n.. aut"
  },
  {
    "path": "docs/reference/knittingpattern/Instruction.rst",
    "chars": 212,
    "preview": "\n.. py:currentmodule:: knittingpattern.Instruction\n\n:py:mod:`Instruction` Module\n============================\n\n.. automo"
  },
  {
    "path": "docs/reference/knittingpattern/InstructionLibrary.rst",
    "chars": 240,
    "preview": "\n.. py:currentmodule:: knittingpattern.InstructionLibrary\n\n:py:mod:`InstructionLibrary` Module\n========================="
  },
  {
    "path": "docs/reference/knittingpattern/KnittingPattern.rst",
    "chars": 228,
    "preview": "\n.. py:currentmodule:: knittingpattern.KnittingPattern\n\n:py:mod:`KnittingPattern` Module\n==============================="
  },
  {
    "path": "docs/reference/knittingpattern/KnittingPatternSet.rst",
    "chars": 240,
    "preview": "\n.. py:currentmodule:: knittingpattern.KnittingPatternSet\n\n:py:mod:`KnittingPatternSet` Module\n========================="
  },
  {
    "path": "docs/reference/knittingpattern/Loader.rst",
    "chars": 192,
    "preview": "\n.. py:currentmodule:: knittingpattern.Loader\n\n:py:mod:`Loader` Module\n=======================\n\n.. automodule:: knitting"
  },
  {
    "path": "docs/reference/knittingpattern/Mesh.rst",
    "chars": 184,
    "preview": "\n.. py:currentmodule:: knittingpattern.Mesh\n\n:py:mod:`Mesh` Module\n=====================\n\n.. automodule:: knittingpatter"
  },
  {
    "path": "docs/reference/knittingpattern/Parser.rst",
    "chars": 192,
    "preview": "\n.. py:currentmodule:: knittingpattern.Parser\n\n:py:mod:`Parser` Module\n=======================\n\n.. automodule:: knitting"
  },
  {
    "path": "docs/reference/knittingpattern/ParsingSpecification.rst",
    "chars": 248,
    "preview": "\n.. py:currentmodule:: knittingpattern.ParsingSpecification\n\n:py:mod:`ParsingSpecification` Module\n====================="
  },
  {
    "path": "docs/reference/knittingpattern/Prototype.rst",
    "chars": 204,
    "preview": "\n.. py:currentmodule:: knittingpattern.Prototype\n\n:py:mod:`Prototype` Module\n==========================\n\n.. automodule::"
  },
  {
    "path": "docs/reference/knittingpattern/Row.rst",
    "chars": 180,
    "preview": "\n.. py:currentmodule:: knittingpattern.Row\n\n:py:mod:`Row` Module\n====================\n\n.. automodule:: knittingpattern.R"
  },
  {
    "path": "docs/reference/knittingpattern/convert/AYABPNGBuilder.rst",
    "chars": 240,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.AYABPNGBuilder\n\n:py:mod:`AYABPNGBuilder` Module\n========================="
  },
  {
    "path": "docs/reference/knittingpattern/convert/AYABPNGDumper.rst",
    "chars": 236,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.AYABPNGDumper\n\n:py:mod:`AYABPNGDumper` Module\n==========================="
  },
  {
    "path": "docs/reference/knittingpattern/convert/InstructionSVGCache.rst",
    "chars": 260,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.InstructionSVGCache\n\n:py:mod:`InstructionSVGCache` Module\n==============="
  },
  {
    "path": "docs/reference/knittingpattern/convert/InstructionToSVG.rst",
    "chars": 248,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.InstructionToSVG\n\n:py:mod:`InstructionToSVG` Module\n====================="
  },
  {
    "path": "docs/reference/knittingpattern/convert/KnittingPatternToSVG.rst",
    "chars": 264,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.KnittingPatternToSVG\n\n:py:mod:`KnittingPatternToSVG` Module\n============="
  },
  {
    "path": "docs/reference/knittingpattern/convert/Layout.rst",
    "chars": 208,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.Layout\n\n:py:mod:`Layout` Module\n=======================\n\n.. automodule:: "
  },
  {
    "path": "docs/reference/knittingpattern/convert/SVGBuilder.rst",
    "chars": 224,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.SVGBuilder\n\n:py:mod:`SVGBuilder` Module\n===========================\n\n.. a"
  },
  {
    "path": "docs/reference/knittingpattern/convert/color.rst",
    "chars": 204,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.color\n\n:py:mod:`color` Module\n======================\n\n.. automodule:: kni"
  },
  {
    "path": "docs/reference/knittingpattern/convert/image_to_knittingpattern.rst",
    "chars": 280,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.image_to_knittingpattern\n\n:py:mod:`image_to_knittingpattern` Module\n====="
  },
  {
    "path": "docs/reference/knittingpattern/convert/index.rst",
    "chars": 317,
    "preview": "The ``knittingpattern.convert`` Module Reference\n================================================\n\n.. toctree::\n   :maxd"
  },
  {
    "path": "docs/reference/knittingpattern/convert/init.rst",
    "chars": 196,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert\n\n:py:mod:`convert` Module\n========================\n\n.. automodule:: knitt"
  },
  {
    "path": "docs/reference/knittingpattern/convert/load_and_dump.rst",
    "chars": 236,
    "preview": "\n.. py:currentmodule:: knittingpattern.convert.load_and_dump\n\n:py:mod:`load_and_dump` Module\n==========================="
  },
  {
    "path": "docs/reference/knittingpattern/index.rst",
    "chars": 304,
    "preview": "The ``knittingpattern`` Module Reference\n========================================\n\n.. toctree::\n   :maxdepth: 2\n\n   init"
  },
  {
    "path": "docs/reference/knittingpattern/init.rst",
    "chars": 196,
    "preview": "\n.. py:currentmodule:: knittingpattern\n\n:py:mod:`knittingpattern` Module\n================================\n\n.. automodule"
  },
  {
    "path": "docs/reference/knittingpattern/utils.rst",
    "chars": 188,
    "preview": "\n.. py:currentmodule:: knittingpattern.utils\n\n:py:mod:`utils` Module\n======================\n\n.. automodule:: knittingpat"
  },
  {
    "path": "docs/reference/knittingpattern/walk.rst",
    "chars": 184,
    "preview": "\n.. py:currentmodule:: knittingpattern.walk\n\n:py:mod:`walk` Module\n=====================\n\n.. automodule:: knittingpatter"
  },
  {
    "path": "docs/test/test_docs.py",
    "chars": 835,
    "preview": "import os\n\n\ndef absjoin(*args):\n    \"\"\"\n    :return: an absolute path to the joined arguments\n    :param args: the parts"
  },
  {
    "path": "docs/test/test_documentation_sources_exist.py",
    "chars": 3711,
    "preview": "#!/usr/bin/python3\n\"\"\"Test the coverage of documentation.\n\nNo function shall be left out by the documentation.\nRun this "
  },
  {
    "path": "docs/test/test_sphinx_build.py",
    "chars": 2078,
    "preview": "\"\"\"Test the building process of the documentation.\n\n- All modules should be documented.\n- All public methods/classes/fun"
  },
  {
    "path": "knittingpattern/Dumper/FileWrapper.py",
    "chars": 1706,
    "preview": "\"\"\"This module provides wrappers for file-like objects\nfor encoding and decoding.\n\n\"\"\"\n\n\nclass BytesWrapper(object):\n   "
  },
  {
    "path": "knittingpattern/Dumper/__init__.py",
    "chars": 369,
    "preview": "\"\"\"Writing objects to files\n\nThis module offers a unified interface to serialize objects to strings\nand save them to fil"
  },
  {
    "path": "knittingpattern/Dumper/file.py",
    "chars": 7437,
    "preview": "\"\"\"Save strings to files.\"\"\"\nfrom io import StringIO, BytesIO\nfrom tempfile import NamedTemporaryFile\nfrom .FileWrapper "
  },
  {
    "path": "knittingpattern/Dumper/json.py",
    "chars": 1357,
    "preview": "\"\"\"Dump objects to JSON.\"\"\"\nimport json\nfrom .file import ContentDumper\n\n\nclass JSONDumper(ContentDumper):\n\n    \"\"\"This "
  },
  {
    "path": "knittingpattern/Dumper/svg.py",
    "chars": 554,
    "preview": "\"\"\"Dump objects to SVG.\"\"\"\nfrom .xml import XMLDumper\nfrom os import remove as remove_file\n\n\nclass SVGDumper(XMLDumper):"
  },
  {
    "path": "knittingpattern/Dumper/xml.py",
    "chars": 707,
    "preview": "\"\"\"Dump objects to XML.\"\"\"\nimport xmltodict\nfrom .file import ContentDumper\n\n\nclass XMLDumper(ContentDumper):\n\n    \"\"\"Us"
  },
  {
    "path": "knittingpattern/IdCollection.py",
    "chars": 2144,
    "preview": "\"\"\"See this module if you like to store object s that have an ``id`` attribute.\n\"\"\"\nfrom collections import OrderedDict\n"
  },
  {
    "path": "knittingpattern/Instruction.py",
    "chars": 20214,
    "preview": "\"\"\"Knitting patterns consist of instructions.\n\nThe :class:`instructions <Instruction>`. that are used in the\n:class:`kni"
  },
  {
    "path": "knittingpattern/InstructionLibrary.py",
    "chars": 4476,
    "preview": "\"\"\"Instructions have  many attributes that do not need to be specified\nin each :class:`knitting pattern set\n<knittingpat"
  },
  {
    "path": "knittingpattern/KnittingPattern.py",
    "chars": 2573,
    "preview": "\"\"\"Here you can find the set of knit instructions in rows.\n\nA :class:`knitting pattern set\n<knittingpattern.KnittingPatt"
  },
  {
    "path": "knittingpattern/KnittingPatternSet.py",
    "chars": 5188,
    "preview": "\"\"\"A set of knitting patterns that can be dumped and loaded.\"\"\"\n\nfrom .convert.AYABPNGDumper import AYABPNGDumper\nfrom ."
  },
  {
    "path": "knittingpattern/Loader.py",
    "chars": 7981,
    "preview": "\"\"\"One can load objects from different locations.\nThis module provides functionality to load objects from different loca"
  },
  {
    "path": "knittingpattern/Mesh.py",
    "chars": 16648,
    "preview": "\"\"\"This module contains the meshes of the knit work.\"\"\"\nfrom abc import ABCMeta, abstractmethod\n\n\nclass Mesh(metaclass=A"
  },
  {
    "path": "knittingpattern/Parser.py",
    "chars": 10255,
    "preview": "\"\"\"In this module you can find the parsing of knitting pattern structures.\"\"\"\n# attributes\n\nID = \"id\"  #: the id of a ro"
  },
  {
    "path": "knittingpattern/ParsingSpecification.py",
    "chars": 3648,
    "preview": "\"\"\"This modules specifies how to convert JSON to knitting patterns.\n\nWhen parsing :class:`knitting patterns\n<knittingpat"
  },
  {
    "path": "knittingpattern/Prototype.py",
    "chars": 3116,
    "preview": "\"\"\"This module contains the :class:`~knittingpattern.Prototype.Prototype`\nthat can be used to create inheritance on obje"
  },
  {
    "path": "knittingpattern/Row.py",
    "chars": 8541,
    "preview": "\"\"\"This module contains the rows of instructions of knitting patterns.\n\nThe :class:`rows <Row>` are part of :class:`knit"
  },
  {
    "path": "knittingpattern/__init__.py",
    "chars": 4042,
    "preview": "\"\"\"The knitting pattern module.\n\nLoad and convert knitting patterns using the convenience functions listed\nbelow.\n\"\"\"\n# "
  },
  {
    "path": "knittingpattern/convert/AYABPNGBuilder.py",
    "chars": 5147,
    "preview": "\"\"\"Convert knitting patterns to png files.\n\nThese png files are used to be fed into the ayab-desktop software.\nThey only"
  },
  {
    "path": "knittingpattern/convert/AYABPNGDumper.py",
    "chars": 1679,
    "preview": "\"\"\"Dump knitting patterns to PNG files compatible with the AYAB software.\n\n\"\"\"\n\nfrom ..Dumper import ContentDumper\nfrom "
  },
  {
    "path": "knittingpattern/convert/InstructionSVGCache.py",
    "chars": 4079,
    "preview": "\"\"\"This module provides functionality to cache instruction SVGs.\"\"\"\nfrom .InstructionToSVG import default_instructions_t"
  },
  {
    "path": "knittingpattern/convert/InstructionToSVG.py",
    "chars": 7364,
    "preview": "\"\"\"This module maps instructions to SVG.\n\nUse :func:`default_instructions_to_svg` to load the svg files provided by\nthis"
  },
  {
    "path": "knittingpattern/convert/KnittingPatternToSVG.py",
    "chars": 5711,
    "preview": "\"\"\"This module provides functionality to convert knitting patterns to SVG.\"\"\"\n\nfrom collections import OrderedDict\n\n#: I"
  },
  {
    "path": "knittingpattern/convert/Layout.py",
    "chars": 11798,
    "preview": "\"\"\"Map ``(x, y)`` coordinates to instructions\n\n\"\"\"\nfrom itertools import chain\nfrom collections import namedtuple\n\n\nINST"
  },
  {
    "path": "knittingpattern/convert/SVGBuilder.py",
    "chars": 6124,
    "preview": "\"\"\"build SVG files\n\n\n\"\"\"\nimport xmltodict\n\n#: an empty svg file as a basis\nSVG_FILE = \"\"\"\n<svg\n   xmlns:ns=\"http://PURL."
  },
  {
    "path": "knittingpattern/convert/__init__.py",
    "chars": 155,
    "preview": "\"\"\"Convert knitting patterns.\n\nUsually you do not need to import this. Convenience functions should be\navailable in the "
  },
  {
    "path": "knittingpattern/convert/color.py",
    "chars": 466,
    "preview": "\"\"\"Functions for color conversion.\"\"\"\nimport webcolors\n\n\ndef convert_color_to_rrggbb(color):\n    \"\"\"The color in \"#RRGGB"
  },
  {
    "path": "knittingpattern/convert/image_to_knittingpattern.py",
    "chars": 2019,
    "preview": "\"\"\"This file lets you convert image files to knitting patterns.\n\n\"\"\"\nimport PIL.Image\nfrom ..Loader import PathLoader\nfr"
  },
  {
    "path": "knittingpattern/convert/load_and_dump.py",
    "chars": 2186,
    "preview": "\"\"\"convinience methods for conversion\n\nBest to use :meth:`decorate_load_and_dump`.\n\n\"\"\"\nfrom functools import wraps\n\n\nde"
  },
  {
    "path": "knittingpattern/convert/test/test_AYABPNGBuilder.py",
    "chars": 4456,
    "preview": "\"\"\"Test creating png files from knitting patterns.\n\nEach pixel is an instruction.\"\"\"\nfrom test_convert import fixture, p"
  },
  {
    "path": "knittingpattern/convert/test/test_SVGBuilder.py",
    "chars": 3220,
    "preview": "from test_convert import fixture, parse_file, raises\nfrom knittingpattern.convert.SVGBuilder import SVGBuilder\nimport io"
  },
  {
    "path": "knittingpattern/convert/test/test_convert.py",
    "chars": 991,
    "preview": "#\n# see https://pytest.org/latest/goodpractices.html\n# for why this module exists\n#\nfrom pytest import fixture, raises, "
  },
  {
    "path": "knittingpattern/convert/test/test_default_instruction_layout.py",
    "chars": 426,
    "preview": "\"\"\"Test rendering propetries of the default instructions.\"\"\"\nfrom test_convert import fixture\nfrom knittingpattern.Instr"
  },
  {
    "path": "knittingpattern/convert/test/test_default_svgs.py",
    "chars": 956,
    "preview": "from test_convert import fixture, os, pytest, HERE\nfrom knittingpattern.convert.InstructionToSVG import \\\n    default_in"
  },
  {
    "path": "knittingpattern/convert/test/test_images.py",
    "chars": 1846,
    "preview": "from test_convert import os, HERE, pytest\nimport re\n\nIMAGES_FOLDER_NAME = \"test_images\"\nIMAGES_FOLDER = os.path.join(HER"
  },
  {
    "path": "knittingpattern/convert/test/test_instruction_to_svg.py",
    "chars": 4100,
    "preview": "from test_images import IMAGES_FOLDER, DEFAULT_FILE,\\\n    IMAGES_FOLDER_NAME, is_knit, is_purl\nfrom test_convert import "
  },
  {
    "path": "knittingpattern/convert/test/test_knittingpattern_to_png.py",
    "chars": 621,
    "preview": "from test_convert import fixture, pytest\nfrom knittingpattern import load_from_relative_file\nimport PIL.Image\n\n\n@fixture"
  },
  {
    "path": "knittingpattern/convert/test/test_layout.py",
    "chars": 11610,
    "preview": "\"\"\"Test the layout of knitting patterns.\"\"\"\nfrom test_convert import fixture\nimport os\nfrom knittingpattern.convert.Layo"
  },
  {
    "path": "knittingpattern/convert/test/test_patterns/add and remove meshes.json",
    "chars": 1484,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"comment\" : {\n    \"content\" : \"4x4 meshes block\",\n    \"type\" : \""
  },
  {
    "path": "knittingpattern/convert/test/test_patterns/block4x4.json",
    "chars": 1487,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"comment\" : {\n    \"content\" : \"4x4 meshes block\",\n    \"type\" : \""
  },
  {
    "path": "knittingpattern/convert/test/test_patterns/cast_on_and_bind_off.json",
    "chars": 1212,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"comment\" : {\n    \"content\" : \"cast on and bind off\",\n    \"type\""
  },
  {
    "path": "knittingpattern/convert/test/test_patterns/small-cafe.json",
    "chars": 3859,
    "preview": "{\n  \"version\" : \"0.1\",\n  \"type\" : \"knitting pattern\", \n  \"comment\" : {\n    \"markdown\" : \"This pattern is taken from [gar"
  },
  {
    "path": "knittingpattern/convert/test/test_patterns/split_up_and_add_rows.json",
    "chars": 1999,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"patterns\" : [\n    {\n      \"id\" : \"knit\",\n      \"name\" : \"A.1\",\n"
  },
  {
    "path": "knittingpattern/convert/test/test_patterns/with hole.json",
    "chars": 1448,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"comment\" : {\n    \"content\" : \"4x4 meshes block\",\n    \"type\" : \""
  },
  {
    "path": "knittingpattern/convert/test/test_png_to_knittingpattern.py",
    "chars": 2030,
    "preview": "from test_convert import fixture, HERE, os\nfrom knittingpattern.convert.image_to_knittingpattern import \\\n    convert_im"
  },
  {
    "path": "knittingpattern/convert/test/test_save_as_svg.py",
    "chars": 2829,
    "preview": "from test_convert import fixture\nfrom knittingpattern import load_from_relative_file\nimport untangle\nfrom itertools impo"
  },
  {
    "path": "knittingpattern/examples/Cafe.json",
    "chars": 12035,
    "preview": "{\n  \"version\" : \"0.1\",\n  \"type\" : \"knitting pattern\", \n  \"comment\" : {\n    \"markdown\" : \"This pattern is taken from [gar"
  },
  {
    "path": "knittingpattern/examples/Charlotte.json",
    "chars": 3194,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"comment\" : {\n    \"content\" : \"This knitting pattern was taken f"
  },
  {
    "path": "knittingpattern/examples/README.md",
    "chars": 865,
    "preview": "Examples\n--------\n\nThis folder contains the pattern that are useful to see how to specify the format.\n\nAlso, have a look"
  },
  {
    "path": "knittingpattern/examples/all-instructions.json",
    "chars": 849,
    "preview": "{\n  \"version\" : \"0.1\",\n  \"type\" : \"knitting pattern\", \n  \"comment\" : {\n    \"markdown\" : \"This pattern is taken from [gar"
  },
  {
    "path": "knittingpattern/examples/block4x4.json",
    "chars": 1487,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"comment\" : {\n    \"content\" : \"4x4 meshes block\",\n    \"type\" : \""
  },
  {
    "path": "knittingpattern/examples/empty.json",
    "chars": 77,
    "preview": "{\n  \"version\" : \"0.1\",\n  \"type\" : \"knitting pattern\", \n  \"patterns\" : [\n  ]\n}"
  },
  {
    "path": "knittingpattern/examples/negative-rendering.json",
    "chars": 2137,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"comment\" : {\n    \"content\" : \"rendering with negative layout in"
  },
  {
    "path": "knittingpattern/examples/new-knitting-pattern.py",
    "chars": 1900,
    "preview": "import json\n\ns = dict()\n\nright_mesh = dict()\n#    type of stitch\n#    k means a knit stitch and p means a purl stitch. T"
  },
  {
    "path": "knittingpattern/instructions/bo.json",
    "chars": 577,
    "preview": "[\n    {\n        \"type\" : \"bo\",\n        \"number of consumed meshes\" : 1,\n        \"number of produced meshes\" : 0,\n       "
  },
  {
    "path": "knittingpattern/instructions/cdd.json",
    "chars": 414,
    "preview": "\n[\n    {\n        \"type\" : \"cdd\",\n        \"number of consumed meshes\" : 3,\n        \"title\" : {\n            \"en-en\" : \"Cen"
  },
  {
    "path": "knittingpattern/instructions/co.json",
    "chars": 768,
    "preview": "[\n    {\n        \"type\" : \"co\",\n        \"number of consumed meshes\" : 0,\n        \"number of produced meshes\" : 1,\n       "
  },
  {
    "path": "knittingpattern/instructions/k2tog.json",
    "chars": 467,
    "preview": "\n[\n    {\n        \"type\" : \"k2tog\",\n        \"title\" : {\n            \"en-en\" : \"Knit 2 Together\"\n        },\n        \"numbe"
  },
  {
    "path": "knittingpattern/instructions/knit.json",
    "chars": 292,
    "preview": "[\n    {\n        \"type\" : \"knit\",\n        \"title\" : {\n            \"en-en\" : \"Knit\",\n            \"de-de\" : \"Rechte Masche\""
  },
  {
    "path": "knittingpattern/instructions/purl.json",
    "chars": 292,
    "preview": "[\n    {\n        \"type\" : \"purl\",\n        \"title\" : {\n            \"en-en\" : \"Purl\",\n            \"de-de\" : \"Linke Masche\"\n"
  },
  {
    "path": "knittingpattern/instructions/skp.json",
    "chars": 490,
    "preview": "\n[\n    {\n        \"type\" : \"skp\",\n        \"number of consumed meshes\" : 2,\n        \"title\" : {\n            \"en-en\" : \"Sli"
  },
  {
    "path": "knittingpattern/instructions/yo.json",
    "chars": 1127,
    "preview": "\n[\n    {\n        \"type\" : \"yo\",\n        \"number of consumed meshes\" : 0,\n        \"title\" : {\n            \"en-en\" : \"Yarn"
  },
  {
    "path": "knittingpattern/test/conftest.py",
    "chars": 339,
    "preview": "\"\"\"This module holds the common test code.\n\n.. seealso:: `pytest good practices\n  <https://pytest.org/latest/goodpractic"
  },
  {
    "path": "knittingpattern/test/pattern/inheritance.json",
    "chars": 1103,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"patterns\" : [\n    {\n      \"id\" : \"color test\",\n      \"name\" : \""
  },
  {
    "path": "knittingpattern/test/pattern/row_mapping_pattern.json",
    "chars": 2053,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"patterns\" : [\n    {\n      \"id\" : \"A.1\",\n      \"name\" : \"A.1\",\n "
  },
  {
    "path": "knittingpattern/test/pattern/row_removal_pattern.json",
    "chars": 803,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"patterns\" : [\n    {\n      \"id\" : \"line\",\n      \"name\" : \"line o"
  },
  {
    "path": "knittingpattern/test/pattern/single_instruction.json",
    "chars": 381,
    "preview": "{\n  \"type\" : \"knitting pattern\",\n  \"version\" : \"0.1\",\n  \"patterns\" : [\n    {\n      \"id\" : \"A.1\",\n      \"name\" : \"A.1\",\n "
  },
  {
    "path": "knittingpattern/test/test_add_and_remove_instructions.py",
    "chars": 2354,
    "preview": "\"\"\"Test the maniipulation of the rows by adding instructions.\"\"\"\nfrom pytest import fixture, raises\nfrom knittingpattern"
  },
  {
    "path": "knittingpattern/test/test_change_row_mapping.py",
    "chars": 8101,
    "preview": "\"\"\"Test if the mapping of the rows is changed and how.\"\"\"\nfrom pytest import fixture, raises\nfrom knittingpattern import"
  },
  {
    "path": "knittingpattern/test/test_default_instructions.py",
    "chars": 1432,
    "preview": "from pytest import fixture\nimport pytest\nfrom knittingpattern.InstructionLibrary import DefaultInstructions, \\\n    defau"
  },
  {
    "path": "knittingpattern/test/test_dump_json.py",
    "chars": 1049,
    "preview": "from pytest import fixture\nfrom unittest.mock import MagicMock\nfrom knittingpattern.Dumper import JSONDumper\nimport json"
  },
  {
    "path": "knittingpattern/test/test_dumper.py",
    "chars": 4570,
    "preview": "from pytest import fixture\nfrom knittingpattern.Dumper import ContentDumper\nfrom io import StringIO, BytesIO\nimport os\n\n"
  },
  {
    "path": "knittingpattern/test/test_example_code.py",
    "chars": 276,
    "preview": "\"\"\"The files contain example code that should work.\"\"\"\n\n\ndef test_load_from_example_and_create_svg():\n    \"\"\"Test :meth:"
  },
  {
    "path": "knittingpattern/test/test_example_rows.py",
    "chars": 1072,
    "preview": "\"\"\"Test properties of rows.\"\"\"\nfrom pytest import fixture, raises\nfrom test_examples import charlotte as _charlotte\n\n\n@f"
  },
  {
    "path": "knittingpattern/test/test_examples.py",
    "chars": 1261,
    "preview": "from pytest import fixture, raises\nimport os\nimport knittingpattern\n\nEXAMPLES_PATH = os.path.join(os.path.dirname(__file"
  },
  {
    "path": "knittingpattern/test/test_id_collection.py",
    "chars": 681,
    "preview": "from pytest import fixture, raises\nfrom knittingpattern.IdCollection import IdCollection\nfrom collections import namedtu"
  },
  {
    "path": "knittingpattern/test/test_instruction.py",
    "chars": 3020,
    "preview": "from pytest import fixture\nfrom knittingpattern.Instruction import Instruction\nimport pytest\n\n\n@fixture\ndef default_inst"
  },
  {
    "path": "knittingpattern/test/test_instruction_library.py",
    "chars": 2550,
    "preview": "from pytest import fixture\nfrom knittingpattern.InstructionLibrary import InstructionLibrary\n\nDESCRIPTION = \"here you ca"
  },
  {
    "path": "knittingpattern/test/test_instruction_row_inheritance.py",
    "chars": 2004,
    "preview": "\"\"\"Test that the color attribute is inherited properly.\"\"\"\nfrom pytest import fixture\nimport pytest\nfrom knittingpattern"
  },
  {
    "path": "knittingpattern/test/test_instructions/recursion/test_instruction_3.json",
    "chars": 62,
    "preview": "\n[\n    {\n        \"type\" : \"test3\",\n        \"value\" : 3\n    }\n]"
  },
  {
    "path": "knittingpattern/test/test_instructions/recursion/test_instruction_4.json",
    "chars": 62,
    "preview": "\n[\n    {\n        \"type\" : \"test4\",\n        \"value\" : 4\n    }\n]"
  },
  {
    "path": "knittingpattern/test/test_instructions/test_instruction_1.json",
    "chars": 62,
    "preview": "\n[\n    {\n        \"type\" : \"test1\",\n        \"value\" : 1\n    }\n]"
  },
  {
    "path": "knittingpattern/test/test_instructions/test_instruction_2.json",
    "chars": 62,
    "preview": "\n[\n    {\n        \"type\" : \"test2\",\n        \"value\" : 2\n    }\n]"
  },
  {
    "path": "knittingpattern/test/test_knittingpattern.py",
    "chars": 1675,
    "preview": "from knittingpattern import new_knitting_pattern\nimport knittingpattern.KnittingPattern as KnittingPatternModule\nfrom kn"
  },
  {
    "path": "knittingpattern/test/test_load_instructions.py",
    "chars": 1104,
    "preview": "from pytest import fixture\nimport os\nfrom knittingpattern.InstructionLibrary import InstructionLibrary\n\n\n@fixture\ndef li"
  },
  {
    "path": "knittingpattern/test/test_loader.py",
    "chars": 2371,
    "preview": "from pytest import fixture\nimport os\nimport pytest\nfrom knittingpattern.Loader import ContentLoader, JSONLoader, PathLoa"
  },
  {
    "path": "knittingpattern/test/test_parsing.py",
    "chars": 1619,
    "preview": "from pytest import fixture, raises\nimport knittingpattern\nimport json\n\nEMPTY_PATTERN = {\n    \"version\": \"0.1\",\n    \"type"
  },
  {
    "path": "knittingpattern/test/test_row_instructions.py",
    "chars": 7767,
    "preview": "\"\"\"These tests access the instructions in rows.\"\"\"\nfrom pytest import fixture, raises\nfrom test_examples import charlott"
  },
  {
    "path": "knittingpattern/test/test_row_mapping.py",
    "chars": 2467,
    "preview": "\"\"\"Test that the rows of a pattern map the right way.\"\"\"\nfrom pytest import fixture\nfrom knittingpattern import load_fro"
  },
  {
    "path": "knittingpattern/test/test_row_meshes.py",
    "chars": 2024,
    "preview": "from pytest import fixture, raises\nfrom knittingpattern import new_knitting_pattern\n\nNO_CONSUMED_MESH = {\"number of cons"
  },
  {
    "path": "knittingpattern/test/test_utilities.py",
    "chars": 629,
    "preview": "from knittingpattern.utils import unique\nimport pytest\n\n\nclass TestUniquenes(object):\n\n    \"\"\"Test the function unique.\""
  },
  {
    "path": "knittingpattern/test/test_walk.py",
    "chars": 2077,
    "preview": "\"\"\"The the ability to sort rows in an order so they can  be knit.\"\"\"\nimport pytest\nfrom knittingpattern import load_from"
  },
  {
    "path": "knittingpattern/utils.py",
    "chars": 730,
    "preview": "\"\"\"This module contains some useful functions.\n\nThe functions work on the standard library or are not specific to\na cert"
  },
  {
    "path": "knittingpattern/walk.py",
    "chars": 1146,
    "preview": "\"\"\"Walk the knitting pattern.\"\"\"\n\n\ndef walk(knitting_pattern):\n    \"\"\"Walk the knitting pattern in a right-to-left fashi"
  },
  {
    "path": "pylintrc",
    "chars": 12605,
    "preview": "[MASTER]\n\n# Specify a configuration file.\n#rcfile=\n\n# Python code to execute, usually for sys.path manipulation such as\n"
  },
  {
    "path": "requirements.in",
    "chars": 38,
    "preview": "setuptools\nPillow\nwebcolors\nxmltodict\n"
  },
  {
    "path": "requirements.txt",
    "chars": 474,
    "preview": "#\n# This file is autogenerated by pip-compile\n# To update, run:\n#\n#    pip-compile --output-file requirements.txt requir"
  },
  {
    "path": "setup.cfg",
    "chars": 279,
    "preview": "[upload_docs]\nupload-dir=build/html\n\n[build_sphinx]\nsource-dir = docs/\nbuild-dir  = build/\nall_files  = 1\n\n[upload_sphin"
  },
  {
    "path": "setup.py",
    "chars": 9150,
    "preview": "#!/usr/bin/python3\n\"\"\"The setup and build script for the library named \"PACKAGE_NAME\".\"\"\"\nimport os\nimport sys\nfrom setu"
  },
  {
    "path": "test-requirements.in",
    "chars": 127,
    "preview": "pytest\npytest-cov\npytest-flakes\npylint\npytest-pep8\ncodeclimate-test-reporter\nuntangle\nsphinx\nsphinx-paramlinks\nsphinx_rt"
  },
  {
    "path": "test-requirements.txt",
    "chars": 1305,
    "preview": "#\n# This file is autogenerated by pip-compile\n# To update, run:\n#\n#    pip-compile --output-file test-requirements.txt t"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the fossasia/knittingpattern GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 162 files (360.5 KB), approximately 96.4k tokens, and a symbol index with 925 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!