Skip to content

Commit

Permalink
Merge pull request #64 from fossasia/add-colors
Browse files Browse the repository at this point in the history
Add colors
  • Loading branch information
niccokunzmann committed Aug 20, 2016
2 parents 0361ed1 + af18d12 commit be44257
Show file tree
Hide file tree
Showing 30 changed files with 222 additions and 36 deletions.
1 change: 1 addition & 0 deletions docs/reference/knittingpattern/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ The ``knittingpattern`` Module Reference
ParsingSpecification
Prototype
Row
utils
walk
11 changes: 11 additions & 0 deletions docs/reference/knittingpattern/utils.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

.. py:currentmodule:: knittingpattern.utils
:py:mod:`utils` Module
======================

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

9 changes: 9 additions & 0 deletions knittingpattern/IdCollection.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,12 @@ def __iter__(self):
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)
12 changes: 12 additions & 0 deletions knittingpattern/KnittingPattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Their functionlality can be found in this module.
"""
from .walk import walk
from .utils import unique


class KnittingPattern(object):
Expand Down Expand Up @@ -73,4 +74,15 @@ def rows_in_knit_order(self):
"""
return walk(self)

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

__all__ = ["KnittingPattern"]
8 changes: 8 additions & 0 deletions knittingpattern/KnittingPatternSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,13 @@ def add_new_pattern(self, id_, name=None):
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"]
16 changes: 15 additions & 1 deletion knittingpattern/Parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,20 @@ def _create_pattern_set(self, pattern, values):
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_START", "MESHES", "COMMENT", "ParsingError",
"default_parser"]
11 changes: 11 additions & 0 deletions knittingpattern/Row.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .Prototype import Prototype
from itertools import chain
from ObservableList import ObservableList
from .utils import unique

COLOR = "color" #: the color of the row

Expand Down Expand Up @@ -133,6 +134,16 @@ def color(self):
"""
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.
Expand Down
12 changes: 12 additions & 0 deletions knittingpattern/test/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""This module holds the common test code.
.. seealso:: `pytest good practices
<https://pytest.org/latest/goodpractices.html>`__ for why this module exists.
"""
import os
import sys

# sys.path makes knittingpattern importable
HERE = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(HERE, "../.."))
__builtins__["HERE"] = HERE
2 changes: 1 addition & 1 deletion knittingpattern/test/test_add_and_remove_instructions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Test the maniipulation of the rows by adding instructions."""
from test_knittingpattern import fixture, HERE, raises
from pytest import fixture, raises
from knittingpattern import load_from_relative_file
from knittingpattern.Instruction import InstructionNotFoundInRow

Expand Down
2 changes: 1 addition & 1 deletion knittingpattern/test/test_change_row_mapping.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Test if the mapping of the rows is changed and how."""
from test_knittingpattern import fixture, raises
from pytest import fixture, raises
from knittingpattern import load_from_relative_file as load_relative_file


Expand Down
3 changes: 2 additions & 1 deletion knittingpattern/test/test_default_instructions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from test_knittingpattern import fixture, pytest
from pytest import fixture
import pytest
from knittingpattern.InstructionLibrary import DefaultInstructions, \
default_instructions

Expand Down
3 changes: 2 additions & 1 deletion knittingpattern/test/test_dump_json.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from test_knittingpattern import fixture, MagicMock
from pytest import fixture
from unittest.mock import MagicMock
from knittingpattern.Dumper import JSONDumper
import json
from knittingpattern.ParsingSpecification import ParsingSpecification
Expand Down
2 changes: 1 addition & 1 deletion knittingpattern/test/test_dumper.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from test_knittingpattern import fixture
from pytest import fixture
from knittingpattern.Dumper import ContentDumper
from io import StringIO, BytesIO
import os
Expand Down
1 change: 0 additions & 1 deletion knittingpattern/test/test_example_code.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""The files contain example code that should work."""
import test_knittingpattern


def test_load_from_example_and_create_svg():
Expand Down
2 changes: 1 addition & 1 deletion knittingpattern/test/test_example_rows.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Test properties of rows."""
from test_knittingpattern import fixture, raises
from pytest import fixture, raises
from test_examples import charlotte as _charlotte


Expand Down
3 changes: 2 additions & 1 deletion knittingpattern/test/test_examples.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from test_knittingpattern import fixture, os, raises
from pytest import fixture, raises
import os
import knittingpattern

EXAMPLES_PATH = os.path.join(os.path.dirname(__file__), "../examples")
Expand Down
2 changes: 1 addition & 1 deletion knittingpattern/test/test_id_collection.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from test_knittingpattern import fixture, raises
from pytest import fixture, raises
from knittingpattern.IdCollection import IdCollection
from collections import namedtuple

Expand Down
2 changes: 1 addition & 1 deletion knittingpattern/test/test_instruction.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from test_knittingpattern import fixture
from pytest import fixture
from knittingpattern.Instruction import Instruction
import pytest

Expand Down
2 changes: 1 addition & 1 deletion knittingpattern/test/test_instruction_library.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from test_knittingpattern import fixture
from pytest import fixture
from knittingpattern.InstructionLibrary import InstructionLibrary

DESCRIPTION = "here you can see how to knit: URL"
Expand Down
3 changes: 2 additions & 1 deletion knittingpattern/test/test_instruction_row_inheritance.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Test that the color attribute is inherited properly."""
from test_knittingpattern import fixture, pytest
from pytest import fixture
import pytest
from knittingpattern import load_from_relative_file


Expand Down
66 changes: 50 additions & 16 deletions knittingpattern/test/test_knittingpattern.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,50 @@
"""This module holds the common test code.
.. seealso:: `pytest good practices
<https://pytest.org/latest/goodpractices.html>`__ for why this module exists.
"""
from pytest import fixture, raises
from unittest.mock import MagicMock
import os
import sys
import pytest

# sys.path makes knittingpattern importable
HERE = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(HERE, "../.."))

__all__ = ["fixture", "raises", "MagicMock", "os", "sys", "pytest"]
from knittingpattern import new_knitting_pattern
import knittingpattern.KnittingPattern as KnittingPatternModule
from knittingpattern.KnittingPattern import KnittingPattern
from unittest.mock import Mock
from test_row_instructions import a1
import knittingpattern
from pytest import fixture


class TestInstructionColors(object):

"""Test KnittingPattern.instruction_colors."""

@fixture
def unique(self, monkeypatch):
mock = Mock()
monkeypatch.setattr(KnittingPatternModule, "unique", mock)
return mock

@fixture
def rows_in_knit_order(self, rows, monkeypatch):
mock = Mock()
monkeypatch.setattr(KnittingPattern, "rows_in_knit_order", mock)
mock.return_value = rows
return mock

@fixture
def rows(self):
return [Mock(), Mock(), Mock()]

@fixture
def knittingpattern(self, rows):
return KnittingPattern(Mock(), Mock(), Mock(), Mock())

def test_result(self, knittingpattern, unique, rows_in_knit_order):
assert knittingpattern.instruction_colors == unique.return_value

def test_call_arguments(self, knittingpattern, unique, rows,
rows_in_knit_order):
knittingpattern.instruction_colors
instruction_colors = [row.instruction_colors for row in rows]
unique.assert_called_once_with(instruction_colors)

def test_chalotte(self, a1):
assert a1.instruction_colors == [None]

def test_cafe(self):
pattern = knittingpattern.load_from().example("Cafe.json").first
colors = ["mocha latte", "dark brown", "brown", "white", ]
assert pattern.instruction_colors == colors
3 changes: 2 additions & 1 deletion knittingpattern/test/test_load_instructions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from test_knittingpattern import fixture, os
from pytest import fixture
import os
from knittingpattern.InstructionLibrary import InstructionLibrary


Expand Down
4 changes: 3 additions & 1 deletion knittingpattern/test/test_loader.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from test_knittingpattern import fixture, os, HERE, pytest
from pytest import fixture
import os
import pytest
from knittingpattern.Loader import ContentLoader, JSONLoader, PathLoader

EXAMPLES_DIRECTORY = os.path.join(HERE, "..", "examples")
Expand Down
2 changes: 1 addition & 1 deletion knittingpattern/test/test_parsing.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from test_knittingpattern import fixture, raises
from pytest import fixture, raises
import knittingpattern
import json

Expand Down
26 changes: 25 additions & 1 deletion knittingpattern/test/test_row_instructions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
"""These tests access the instructions in rows."""
from test_knittingpattern import fixture, raises
from pytest import fixture, raises
from test_examples import charlotte as _charlotte
from knittingpattern.Instruction import InstructionNotFoundInRow
import pytest
from knittingpattern.Row import Row
from unittest.mock import Mock
from knittingpattern.Parser import default_parser


@fixture
Expand Down Expand Up @@ -255,3 +259,23 @@ def test_first_instruction(self, a1):
def test_last_instruction(self, a1):
for row in a1.rows:
assert row.last_instruction == row.instructions[-1]


class TestInstructionColors(object):

"""Test Row.instruction_colors."""

@pytest.mark.parametrize("specs,result", [
([{}, {}], [None]), ([{"color": 1}], [1]),
([{"color": 3}, {}, {"color": 123}, {"color": 123}], [3, None, 123])])
@pytest.mark.parametrize("row_spec,default_color", [
({"color": "green"}, "green"), ({}, None)])
def test_row_instructions(self, specs, result, row_spec, default_color):
result = result[:]
for i, color in enumerate(result):
if color is None:
result[i] = default_color
row = Row("id", row_spec, default_parser())
for instruction in specs:
row.instructions.append(instruction)
assert row.instruction_colors == result
2 changes: 1 addition & 1 deletion knittingpattern/test/test_row_mapping.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Test that the rows of a pattern map the right way."""
from test_knittingpattern import fixture
from pytest import fixture
from knittingpattern import load_from_object
from knittingpattern.Loader import JSONLoader as Loader

Expand Down
2 changes: 1 addition & 1 deletion knittingpattern/test/test_row_meshes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from test_knittingpattern import fixture, raises
from pytest import fixture, raises
from knittingpattern import new_knitting_pattern

NO_CONSUMED_MESH = {"number of consumed meshes": 0}
Expand Down
19 changes: 19 additions & 0 deletions knittingpattern/test/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from knittingpattern.utils import unique
import pytest


class TestUniquenes(object):

"""Test the function unique."""

@pytest.mark.parametrize("input,expected_result", [
([], []), ([[1, 1, 1, 1, 1]], [1]),
([[1, 2, 3], [4, 3, 2, 1]], [1, 2, 3, 4]),
([[None, 4], [4, 6, None]], [None, 4, 6]),
([[[], [1]], [[1], [0], []]], [[], [1], [0]])])
@pytest.mark.parametrize("use_generator", [True, False])
def test_results(self, input, expected_result, use_generator):
if use_generator:
input = [(element for element in listing) for listing in input]
result = unique(input)
assert result == expected_result
2 changes: 1 addition & 1 deletion knittingpattern/test/test_walk.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""The the ability to sort rows in an order so they can be knit."""
from test_knittingpattern import pytest, HERE
import pytest
from knittingpattern import load_from_relative_file, new_knitting_pattern
from knittingpattern.walk import walk

Expand Down
25 changes: 25 additions & 0 deletions knittingpattern/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""This module contains some useful functions.
The functions work on the standart library or are not specific to
a certain exising module.
"""


def unique(iterables):
"""Create an iterable from the iterables that contains each element once.
:return: an iterable over the iterables. Each element of the result
appeard only once in the result. They are oredered by the first
occurrence in the iterables.
"""
included_elements = []

def included(element):
result = element in included_elements
included_elements.append(element)
return result
return [element for elements in iterables for element in elements
if not included(element)]


__all__ = ["unique"]

0 comments on commit be44257

Please sign in to comment.