Skip to content

Commit

Permalink
Merge pull request #8 from quiqueporta/migrate-to-github-actions
Browse files Browse the repository at this point in the history
Migrate to GitHub actions
  • Loading branch information
quiqueporta authored Oct 27, 2022
2 parents a105cc1 + d6fd61f commit 9fb2986
Show file tree
Hide file tree
Showing 14 changed files with 120 additions and 114 deletions.
4 changes: 0 additions & 4 deletions .coveragerc

This file was deleted.

4 changes: 1 addition & 3 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -r requirements-test.txt
pip install coveralls
python setup.py -q develop
- name: Test with mamba
run: |
PYTHONPATH=$PYTHONPATH:. mamba --enable-coverage
PYTHONPATH=$PYTHONPATH:. mamba -f documentation
5 changes: 3 additions & 2 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Original Author
---------------
Author
------
Quique Porta https://github.com/quiqueporta


Expand All @@ -8,3 +8,4 @@ Contributors
William Travis Jones https://github.com/wtjones
David Arias http://davidarias.net
Hugo Leonardo Costa e Silva https://github.com/hugoleodev
Jesse Heitler https://github.com/jesseh
11 changes: 11 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
Changelog
=========

2.0.0 (2022-10-27)
------------------

- Rename CannotBeChangeException to CannotBeChanged
- Rename InvariantReturnValueException to InvariantMustReturnBool
- Rename NotDeclaredArgsException to ConstructorWithoutArguments
- Rename ViolatedInvariantException to InvariantViolation
- Simplifly invariants now receives `self` attribute only
- Fix replace_mutable_kwargs_with_immutable_types for `set` kwargs


1.5.0 (2020-12-07)
------------------

Expand Down
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM python:3.10-alpine

WORKDIR /app

ENV PYTHONPATH="/app"

COPY ./requirements-test.txt /

RUN pip install --upgrade pip
RUN pip install -r /requirements-test.txt

COPY . /app
33 changes: 14 additions & 19 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Value Object
============

|Version Number| |Build Status| |Coverage Status| |Python Version| |License MIT|
|Version Number| |Python Version| |License MIT|


Based on Ruby Gem by NoFlopSquad (https://github.com/noflopsquad/value-object)
Expand Down Expand Up @@ -43,7 +43,7 @@ Constructor and field readers
# 2
point.x = 5
# CannotBeChangeException: You cannot change values from a Value Object, create a new one
# CannotBeChanged: You cannot change values from a Value Object, create a new one
class Date(ValueObject):
def __init__(self, day, month, year):
Expand All @@ -61,7 +61,7 @@ Constructor and field readers
# 2015
date.month = 5
# CannotBeChangeException: You cannot change values from a Value Object, create a new one
# CannotBeChanged: You cannot change values from a Value Object, create a new one
Equality based on field values
Expand Down Expand Up @@ -115,6 +115,8 @@ Hash code based on field values
Invariants
~~~~~~~~~~

Invariants **must** return a boolean value.

.. code-block:: python
from simple_value_object import ValueObject, invariant
Expand All @@ -125,18 +127,18 @@ Invariants
pass
@invariant
def inside_first_quadrant(cls, instance):
return instance.x > 0 and instance.y > 0
def inside_first_quadrant(self):
return self.x > 0 and self.y > 0
@invariant
def x_less_than_y(cls, instance):
return instance.x < instance.y
def x_less_than_y(self):
return self.x < self.y
Point(-5, 3)
#ViolatedInvariantException: Args violates invariant: inside_first_cuadrant
#InvariantViolation: inside_first_cuadrant
Point(6, 3)
#ViolatedInvariantException: Args violates invariant: x_less_than_y
#InvariantViolation: x_less_than_y
Point(1,3)
#<__main__.Point at 0x7f2bd043c780>
Expand Down Expand Up @@ -165,18 +167,11 @@ Test

.. code-block:: sh
> pip install -r requirements-test.txt
> PYTHONPATH=$PYTHONPATH:. mamba
.. |Version Number| image:: https://img.shields.io/badge/version-1.5.0-blue.svg
> $ docker/test
.. |Build Status| image:: https://travis-ci.org/quiqueporta/simple-value-object.svg?branch=master
:target: https://travis-ci.org/quiqueporta/simple-value-object
.. |Coverage Status| image:: https://coveralls.io/repos/quiqueporta/simple-value-object/badge.svg?branch=master&service=github
:target: https://coveralls.io/github/quiqueporta/simple-value-object?branch=master
.. |Version Number| image:: https://img.shields.io/badge/version-2.0.0-blue.svg

.. |License MIT| image:: https://img.shields.io/github/license/quiqueporta/simple-value-object

.. |Python Version| image:: https://img.shields.io/badge/python-3.4,_3.5,_3.6,_3.7-blue.svg
.. |Python Version| image:: https://img.shields.io/badge/python-3.6,_3.7,_3.8,_3.9,_3.10-blue.svg
4 changes: 4 additions & 0 deletions docker/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh

docker build -t simple-value-object:latest .
docker run --rm -it simple-value-object:latest mamba --f documentation
2 changes: 1 addition & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
expects==0.9.0
mamba==0.11.0
mamba==0.11.2
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
license='MIT/X11',
author='Quique Porta',
author_email='quiqueporta@gmail.com',
description='A simple mixin for create Value Objects',
description='A simple mixin to create Value Objects',
long_description=open('README.rst').read(),
url='https://github.com/quiqueporta/value-object',
download_url='https://github.com/quiqueporta/simple-value-object/releases',
Expand Down
4 changes: 1 addition & 3 deletions simple_value_object/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# -*- coding: utf-8 -*-

from .value_object import ValueObject
from .decorators import invariant

VERSION = (1, 5, 0, 'final')
VERSION = (2, 0, 0, 'final')
__version__ = VERSION


Expand Down
5 changes: 3 additions & 2 deletions simple_value_object/decorators.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
def invariant(func):
def invariant_func_wrapper(cls, instance):
return func(cls, instance)
def invariant_func_wrapper(instance):
return func(instance)

invariant_func_wrapper.name = func.__name__
return invariant_func_wrapper
28 changes: 14 additions & 14 deletions simple_value_object/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
class NotDeclaredArgsException(Exception):
def __init__(self, *args, **kwargs):
super(NotDeclaredArgsException, self).__init__(
'No arguments declared in __init__'
)
class SimpleValueObjectException(Exception):
pass


class ConstructorWithoutArguments(SimpleValueObjectException):
def __init__(self):
super().__init__('No arguments declared in __init__')

class CannotBeChangeException(Exception):
def __init__(self, *args, **kwargs):
super(CannotBeChangeException, self).__init__(

class CannotBeChanged(SimpleValueObjectException):
def __init__(self):
super().__init__(
'You cannot change values from a Value Object, create a new one'
)


class ViolatedInvariantException(Exception):
class InvariantViolation(SimpleValueObjectException):
pass


class InvariantReturnValueException(Exception):
def __init__(self, *args, **kwargs):
super(InvariantReturnValueException, self).__init__(
'Invariants must return a boolean value'
)
class InvariantMustReturnBool(SimpleValueObjectException):
def __init__(self):
super().__init__('Invariants must return a boolean value')
67 changes: 28 additions & 39 deletions simple_value_object/value_object.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import sys
import inspect
import sys

from .exceptions import (
CannotBeChangeException,
InvariantReturnValueException,
NotDeclaredArgsException,
ViolatedInvariantException
CannotBeChanged,
ConstructorWithoutArguments,
InvariantMustReturnBool,
InvariantViolation
)

MIN_NUMBER_ARGS = 1
INVARIANT_NAME = 0
INVARIANT_METHOD = 1


class ValueObject(object):
class ValueObject:

def __new__(cls, *args, **kwargs):
self = super(ValueObject, cls).__new__(cls)
self = super().__new__(cls)

args_spec = ArgsSpec(self.__init__)

def check_class_initialization():
init_constructor_without_arguments = len(args_spec.args) <= MIN_NUMBER_ARGS

if init_constructor_without_arguments:
raise NotDeclaredArgsException()
raise ConstructorWithoutArguments()

def replace_mutable_kwargs_with_immutable_types():
for arg, value in kwargs.items():
Expand Down Expand Up @@ -61,31 +61,27 @@ def override_default_values_with_args():

def check_invariants():
for invariant in obtain_invariants():
if not invariant_execute(invariant[INVARIANT_METHOD]):
raise ViolatedInvariantException(
'Args violates invariant: {}'.format(
invariant[INVARIANT_NAME]
)
)

def invariant_execute(invariant):
return_value = invariant(self, self)
if is_invariant_violated(invariant):
raise InvariantViolation(f'Invariant violation: {invariant.name}')

if not isinstance(return_value, bool):
raise InvariantReturnValueException()

return return_value
def obtain_invariants():
for invariant in filter(is_invariant, cls.__dict__.values()):
yield invariant

def is_invariant(method):
try:
return 'invariant_func_wrapper' in str(method) and '__init__' not in str(method)
except TypeError:
return method.__name__ == 'invariant_func_wrapper'
except AttributeError:
return False

def obtain_invariants():
invariants = [(member[INVARIANT_NAME], member[INVARIANT_METHOD]) for member in inspect.getmembers(cls, is_invariant)]
for invariant in invariants:
yield invariant
def is_invariant_violated(invariant):
invariant_result = invariant(self)

if not isinstance(invariant_result, bool):
raise InvariantMustReturnBool()

return invariant_result is False


check_class_initialization()
replace_mutable_kwargs_with_immutable_types()
Expand All @@ -95,7 +91,7 @@ def obtain_invariants():
return self

def __setattr__(self, name, value):
raise CannotBeChangeException()
raise CannotBeChanged()

def __eq__(self, other):
if other is None:
Expand All @@ -122,18 +118,11 @@ def hash(self):
return hash(repr(self))


class ArgsSpec(object):
class ArgsSpec:

def __init__(self, method):
try:
if sys.version_info.major == 2:
self.__argspec = inspect.getargspec(method)
self.__varkw = self.__argspec.keywords
else:
self.__argspec = inspect.getfullargspec(method)
self.__varkw = self.__argspec.varkw
except TypeError:
raise NotDeclaredArgsException()
self.__argspec = inspect.getfullargspec(method)
self.__varkw = self.__argspec.varkw

@property
def args(self):
Expand All @@ -158,7 +147,7 @@ def __hash__(self):
return id(self)

def _immutable(self, *args, **kwargs):
raise CannotBeChangeException()
raise CannotBeChanged()

__setitem__ = _immutable
__delitem__ = _immutable
Expand Down
Loading

0 comments on commit 9fb2986

Please sign in to comment.