Source code for knittingpattern.Mesh

"""This module contains the meshes of the knit work."""
from abc import ABCMeta, abstractmethod


[docs]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!"
[docs] 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()
[docs] 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]
[docs] 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()
[docs] 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 )
[docs] 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()
[docs] def connect_to(self, other_mesh): """Create a connection to an other mesh. .. warning:: Both meshes need to be disocnnected 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)
[docs] 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()
[docs] 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()
[docs] def as_consumed_mesh(self): """The consumed part to this mesh.""" self._assert_is_consumed() return self._as_consumed_mesh()
[docs] def is_mesh(self): """Whether this object is a mesh. :return: :obj:`True` :rtype: bool """ return True
[docs] 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)
[docs] 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
[docs]class ProducedMesh(Mesh): """A :class:`~knittingpattern.Mesh.Mesh` that has a producing instruction """
[docs] 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
[docs]class ConsumedMesh(Mesh): """A mesh that is only consumed by an instruction"""
[docs] 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"]