Skip to content

Commit

Permalink
Merge branch 'release/0.9.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
Przemyslaw Jan Pietrzak committed Feb 7, 2018
2 parents 8273b60 + d87f34b commit b011cda
Show file tree
Hide file tree
Showing 23 changed files with 216 additions and 70 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ pymonet.egg-info
dist
docs/dist
monet
_build
_build
build
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test-with-coverage:
py.test ./tests --cov=./pymonet/

lint:
flake8 ./pymonet ./tests --max-line-length=120
flake8 ./pymonet ./tests ./testers --max-line-length=120

lint-docs:
pydocstyle ./pymonet --add-ignore=D100,D101,D102,D103,D104,D105,D107,D200,D205,D400,D401
Expand Down
4 changes: 2 additions & 2 deletions conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
project = 'pyMonet'
copyright = '2017, Przemyslaw Jan Pietrzak'
author = 'Przemyslaw Jan Pietrzak'
version = '0.9.0'
release = '0.9.0'
version = '0.9.1'
release = '0.9.1'
language = None
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
pygments_style = 'sphinx'
Expand Down
32 changes: 32 additions & 0 deletions docs/semigroups.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Semigroups
*********

.. code-block:: python
:caption: example_semigroup.py
:name: example_semigroup-py
from pymonet.semigroups import All, First, Map, Sum
All(True).concat(All(False)) # All<False>
All(True).concat(All(True)) # All<True>
All(True) == All(True) # True
All(True) == All(False) # False
ingredient1 = Map({'score': Sum(1), 'won': All(True), 'captain': First('captain america')})
ingredient2 = Map({'score': Sum(2), 'won': All(True), 'captain': First('iron man')})
ingredient1.concat(ingredient2) # Map<{'score': Sum(3), 'won': All(True), 'captain': First('captain america')}>
.. autoclass:: pymonet.semigroups.All
:members: __init__, concat, fold

.. autoclass:: pymonet.semigroups.One
:members: __init__, concat, fold

.. autoclass:: pymonet.semigroups.First
:members: __init__, concat, fold

.. autoclass:: pymonet.semigroups.Map
:members: __init__, concat, fold


4 changes: 2 additions & 2 deletions docs/task.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ Task
*********

.. code-block:: python
:caption: example_box.py
:name: example_box-py
:caption: example_task.py
:name: example_task-py
from pymonet.task import Task
Expand Down
1 change: 1 addition & 0 deletions index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ High abstract python library for functional programming. Contains algebraic data
./docs/try
./docs/task
./docs/validation
./docs/semigroups
./docs/utils
31 changes: 31 additions & 0 deletions pymonet/semigroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,58 @@ def __eq__(self, other):
def fold(self, fn):
return fn(self.value)

@classmethod
def neutral(cls):
return cls(cls.neutral_element)


class Sum(Semigroup):

neutral_element = 0

def __str__(self): # pragma: no cover
return 'Sum[value={}]'.format(self.value)

def concat(self, semigroup):
return Sum(self.value + semigroup.value)


class All(Semigroup):

neutral_element = True

def __str__(self): # pragma: no cover
return 'All[value={}]'.format(self.value)

def concat(self, semigroup):
return All(self.value and semigroup.value)


class One(Semigroup):

neutral_element = False

def __str__(self): # pragma: no cover
return 'One[value={}]'.format(self.value)

def concat(self, semigroup):
return One(self.value or semigroup.value)


class First(Semigroup):

def __str__(self): # pragma: no cover
return 'Fist[value={}]'.format(self.value)

def concat(self, semigroup):
return First(self.value)


class Map(Semigroup):

def __str__(self): # pragma: no cover
return 'Map[value={}]'.format(self.value)

def concat(self, semigroup):
return Map(
{key: value.concat(semigroup.value[key]) for key, value in self.value.items()}
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
setup(
name='pymonet',
packages=['pymonet'],
version='0.9.0',
version='0.9.1',
description='High abstract python library for functional programming. Contains algebraic data structures known from Haskell or Scala.',
author='Przemyslaw Jan Pietrzak',
author_email='[email protected]',
url='https://github.com/przemyslawjanpietrzak/pyMonet',
download_url='https://github.com/przemyslawjanpietrzak/pyMonet/archive/0.9.0.tar.gz',
download_url='https://github.com/przemyslawjanpietrzak/pyMonet/archive/0.9.1.tar.gz',
keywords=['functional-programming', 'monads', 'functors', 'semigroups'],
classifiers=[],
)
Empty file added testers/__init__.py
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
17 changes: 17 additions & 0 deletions testers/monoid_law_tester.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class MonoidLawTester:

def __init__(self, monoid, value):
self.monoid = monoid
self.value = value

def left_identity_test(self):
monoid = self.monoid(self.value)
assert monoid.concat(monoid.neutral()) == monoid

def right_identity_test(self):
monoid = self.monoid(self.value)
assert monoid.neutral().concat(monoid) == monoid

def test(self):
self.left_identity_test()
self.right_identity_test()
23 changes: 23 additions & 0 deletions testers/semigroup_law_tester.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class SemigroupLawTester:

def __init__(self, semigroup, value1, value2, value3, result):
self.semigroup = semigroup
self.value1 = value1
self.value2 = value2
self.value3 = value3
self.result = result

def associativity_test(self):

x = self.semigroup(self.value1)\
.concat(self.semigroup(self.value2))\
.concat(self.semigroup(self.value3))

y = self.semigroup(self.value1).concat(
self.semigroup(self.value2).concat(self.semigroup(self.value3))
)

assert x == y == self.result

def test(self):
self.associativity_test()
8 changes: 4 additions & 4 deletions tests/test_box.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from tests.monad_law_tester import MonadLawTester
from tests.functor_law_tester import FunctorLawTester
from tests.monad_transform_tester import MonadTransformTester
from tests.applicative_law_tester import ApplicativeLawTester
from testers.monad_law_tester import MonadLawTester
from testers.functor_law_tester import FunctorLawTester
from testers.monad_transform_tester import MonadTransformTester
from testers.applicative_law_tester import ApplicativeLawTester

from pymonet.box import Box
from pymonet.utils import increase
Expand Down
8 changes: 4 additions & 4 deletions tests/test_either.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from tests.monad_law_tester import MonadLawTester
from tests.functor_law_tester import FunctorLawTester
from tests.monad_transform_tester import MonadTransformTester
from tests.applicative_law_tester import ApplicativeLawTester
from testers.monad_law_tester import MonadLawTester
from testers.functor_law_tester import FunctorLawTester
from testers.monad_transform_tester import MonadTransformTester
from testers.applicative_law_tester import ApplicativeLawTester

from pymonet.either import Left, Right
from pymonet.utils import increase
Expand Down
8 changes: 4 additions & 4 deletions tests/test_lazy.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from tests.applicative_law_tester import ApplicativeLawTester
from tests.functor_law_tester import FunctorLawTester
from tests.monad_transform_tester import MonadTransformTester
from tests.monad_law_tester import MonadLawTester
from testers.applicative_law_tester import ApplicativeLawTester
from testers.functor_law_tester import FunctorLawTester
from testers.monad_transform_tester import MonadTransformTester
from testers.monad_law_tester import MonadLawTester

from pymonet.lazy import Lazy
from pymonet.validation import Validation
Expand Down
8 changes: 4 additions & 4 deletions tests/test_maybe.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from tests.monad_law_tester import MonadLawTester
from tests.functor_law_tester import FunctorLawTester
from tests.monad_transform_tester import MonadTransformTester
from tests.applicative_law_tester import ApplicativeLawTester
from testers.monad_law_tester import MonadLawTester
from testers.functor_law_tester import FunctorLawTester
from testers.monad_transform_tester import MonadTransformTester
from testers.applicative_law_tester import ApplicativeLawTester

from pymonet.maybe import Maybe
from pymonet.box import Box
Expand Down
119 changes: 80 additions & 39 deletions tests/test_semigroups.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,102 @@
from hypothesis import given
from hypothesis.strategies import text, integers, booleans
from hypothesis.strategies import text, integers, booleans, dictionaries

from pymonet.semigroups import Sum, All, First, Map
from pymonet.utils import identity
from testers.semigroup_law_tester import SemigroupLawTester
from testers.monoid_law_tester import MonoidLawTester

ingredient1 = Map({'score': Sum(1), 'won': All(True), 'captain': First('captain america')})
ingredient2 = Map({'score': Sum(2), 'won': All(True), 'captain': First('iron man')})
ingredient3 = Map({'score': Sum(3), 'won': All(False), 'captain': First('Batman')})
from pymonet.semigroups import Sum, All, One, First, Map
from pymonet.utils import identity


@given(integers(), integers(), integers())
def test_sum(x, y, z):
assert Sum(x).concat(Sum(y)) == Sum(x + y)
assert Sum(x).concat(
Sum(y).concat(Sum(z))
) == Sum(x + y + z)
assert Sum(x).concat(Sum(y)).concat(Sum(z)) == Sum(x + y + z)

SemigroupLawTester(
semigroup=Sum,
value1=x,
value2=y,
value3=z,
result=Sum(x + y + z)
).test()

@given(booleans(), booleans(), booleans())
def test_all(bool1, bool2, bool3):

assert All(bool1).concat(All(bool2)) == All(bool1 and bool2)
assert All(bool1).concat(
All(bool2).concat(All(bool3))
) == All(bool1 and bool2 and bool3)
assert All(bool1).concat(All(bool2)).concat(All(bool3)) == All(bool1 and bool2 and bool3)
@given(integers())
def test_sum_monoid(integer):
MonoidLawTester(
monoid=Sum,
value=integer
).test()


@given(text(), text(), text())
def test_first(text1, text2, text3):
assert First(text1).concat(First(text2)) == First(text1)
assert First(text1).concat(First(text2)).concat(First(text3)) == First(text1)
assert First(text1).concat(
First(text2).concat(First(text3))
) == First(text1)
@given(booleans(), booleans(), booleans())
def test_all(bool1, bool2, bool3):
SemigroupLawTester(
semigroup=All,
value1=bool1,
value2=bool2,
value3=bool3,
result=All(bool1 and bool2 and bool3)
).test()


def test_map():
@given(booleans())
def test_all_monoid(boolean):
MonoidLawTester(
monoid=All,
value=boolean
).test()

assert ingredient1.concat(ingredient2) == Map(
{'score': Sum(3), 'won': All(True), 'captain': First('captain america')}
)

assert ingredient1.concat(ingredient2).concat(ingredient3) == Map(
{'score': Sum(6), 'won': All(False), 'captain': First('captain america')}
)
@given(booleans(), booleans(), booleans())
def test_one(bool1, bool2, bool3):
SemigroupLawTester(
semigroup=One,
value1=bool1,
value2=bool2,
value3=bool3,
result=One(bool1 or bool2 or bool3)
).test()

assert ingredient1.concat(ingredient2.concat(ingredient3)) == Map(
{'score': Sum(6), 'won': All(False), 'captain': First('captain america')}
)

@given(booleans())
def test_one_monoid(boolean):
MonoidLawTester(
monoid=One,
value=boolean
).test()

@given(integers(), text(), booleans())
def test_fold(integer, text, boolean):

dictionary = {'key': 'value'}
@given(text(), text(), text())
def test_first(text1, text2, text3):
SemigroupLawTester(
semigroup=First,
value1=text1,
value2=text2,
value3=text3,
result=First(text1)
).test()


@given(
integers(), integers(), integers(),
booleans(), booleans(), booleans(),
text(), text(), text()
)
def test_map(integer1, integer2, integer3, boolean1, boolean2, boolean3, text1, text2, text3):
SemigroupLawTester(
semigroup=Map,
value1={'sum': Sum(integer1), 'all': All(boolean1), 'first': First(text1)},
value2={'sum': Sum(integer2), 'all': All(boolean2), 'first': First(text2)},
value3={'sum': Sum(integer3), 'all': All(boolean3), 'first': First(text3)},
result=Map({
'sum': Sum(integer1 + integer2 + integer3),
'all': All(boolean1 and boolean2 and boolean3),
'first': First(text1)
})
).test()


@given(integers(), text(), booleans(), dictionaries(keys=text(), values=integers()))
def test_fold(integer, text, boolean, dictionary):

assert First(text).fold(identity) is text
assert All(boolean).fold(identity) is boolean
Expand Down
4 changes: 2 additions & 2 deletions tests/test_task.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from tests.functor_law_tester import FunctorLawTester
from tests.monad_law_tester import MonadLawTester
from testers.functor_law_tester import FunctorLawTester
from testers.monad_law_tester import MonadLawTester

from pymonet.task import Task
from pymonet.utils import identity, increase
Expand Down
Loading

0 comments on commit b011cda

Please sign in to comment.