Skip to content

Commit

Permalink
Adding missing methods/properties to complete stateful entities.
Browse files Browse the repository at this point in the history
Missing documentation yet.
  • Loading branch information
menegazzo committed Aug 4, 2014
1 parent 0f18ac8 commit 4975060
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 60 deletions.
49 changes: 49 additions & 0 deletions travispy/_tests/test_stateful.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from travispy.entities._stateful import Stateful
import pytest


#===================================================================================================
# Test
#===================================================================================================
class Test:

@pytest.mark.parametrize(
'state, created, queued, started, passed, failed, errored, canceled, ready, pending, running, finished, successful, unsuccessful, color, green, yellow, red', [

This comment has been minimized.

Copy link
@nicoddemus

nicoddemus Aug 4, 2014

Contributor

Suggestion: for True and False properties, you could replace all explicit calls for a single set of expected values, like so:

    @pytest.mark.parametrize(
    'state, expected_true_properties, color'
    [
        (Stateful.Created, set('created', 'pending', 'yellow'), Stateful.YELLOW),
    ]
    def test_stateful(self, state, expected_true_properties, color):
        # ...
        all_properties = ['created', 'queued', 'started', ...]
        for prop in all_properties:
             assert getattr(state, prop) == prop in expected_true_properties
        assert state.color == color

Seems easier to maintain the state table this way. 😄

This comment has been minimized.

Copy link
@menegazzo

menegazzo Aug 4, 2014

Author Owner

Nice tip!
Changes already made and pushed.

(Stateful.CREATED, True, False, False, False, False, False, False, False, True, False, False, False, False, Stateful.YELLOW, False, True, False),
(Stateful.QUEUED, True, True, False, False, False, False, False, False, True, False, False, False, False, Stateful.YELLOW, False, True, False),
(Stateful.STARTED, True, True, True, False, False, False, False, False, True, True, False, False, False, Stateful.YELLOW, False, True, False),
(Stateful.PASSED, True, True, True, True, False, False, False, False, False, False, True, True, False, Stateful.GREEN, True, False, False),
(Stateful.FAILED, True, True, True, False, True, False, False, False, False, False, True, False, True, Stateful.RED, False, False, True),
(Stateful.ERRORED, True, True, True, False, False, True, False, False, False, False, True, False, True, Stateful.RED, False, False, True),
(Stateful.CANCELED, True, True, True, False, False, False, True, False, False, False, True, False, True, Stateful.RED, False, False, True),
(Stateful.READY, True, True, True, False, False, False, False, True, False, False, True, False, False, Stateful.GREEN, True, False, False),
])
def testStateful(self, state, created, queued, started, passed, failed, errored, canceled, ready, pending, running, finished, successful, unsuccessful, color, green, yellow, red):

This comment has been minimized.

Copy link
@nicoddemus

nicoddemus Aug 4, 2014

Contributor

Minor: shouldn't this be test_stateful to keep naming consistency with the rest of the code?

This comment has been minimized.

Copy link
@menegazzo

menegazzo Aug 4, 2014

Author Owner

Changed. Tks!

stateful = Stateful(None)

assert hasattr(stateful, 'state') == False
with pytest.raises(AttributeError):
stateful.created

stateful.state = None
with pytest.raises(ValueError):
stateful.created

stateful.state = state
assert stateful.created == created
assert stateful.queued == queued
assert stateful.started == started
assert stateful.passed == passed
assert stateful.failed == failed
assert stateful.errored == errored
assert stateful.canceled == canceled
assert stateful.ready == ready
assert stateful.pending == pending
assert stateful.running == running
assert stateful.finished == finished
assert stateful.successful == successful
assert stateful.unsuccessful == unsuccessful
assert stateful.color == color
assert stateful.green == green
assert stateful.yellow == yellow
assert stateful.red == red
4 changes: 0 additions & 4 deletions travispy/entities/_restartable.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ class Restartable(Stateful):
Base class for restartable entities such as :class:`.Build` and :class:`.Job`.
'''

__slots__ = [
'state',
]

def cancel(self):
'''
Method responsible for canceling current action of this object.
Expand Down
148 changes: 101 additions & 47 deletions travispy/entities/_stateful.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,23 @@
class Stateful(Entity):
'''
Base class for stateful entities such as :class:`.Repo`, :class:`.Build` and :class:`.Job`.
:ivar str state:
Current state. Possible values are:
- created

This comment has been minimized.

Copy link
@nicoddemus

nicoddemus Aug 4, 2014

Contributor

Since you defined this strings as constants in Stateful (like Stateful.CREATED), I think your docs should encourage using that instead of relying on the strings themselves. This leaves room to changing the underlying type later if needed, or the constant values themselves.

This comment has been minimized.

Copy link
@menegazzo

menegazzo Aug 4, 2014

Author Owner

That was always my intention but I left documentation as last thing after done the implementation.
Already created the documentation and pushed.

Tks for the advice, anyway. ;)

- queued
- started
- passed
- failed
- errored
- canceled
- ready
'''


__slots__ = ['state']

# States ---------------------------------------------------------------------------------------
CANCELED = 'canceled'
CREATED = 'created'
ERRORED = 'errored'
Expand All @@ -18,82 +33,121 @@ class Stateful(Entity):
QUEUED = 'queued'
READY = 'ready'
STARTED = 'started'

STATES = [
'canceled',
'created',
'errored',
'failed',
'passed',
'queued',
'ready',
'started',
]

__slots__ = [
'created?',
'errored?',
'failed?',
'finished?',
'green?',
'passed?',
'pending?',
'queued?',
'red?',
'running?',
'started?',
'successful?',
'unsuccessful?',
'yellow?',
'color',
'state',
]

# Colors ---------------------------------------------------------------------------------------
GREEN = 'green'
YELLOW = 'yellow'
RED = 'red'

@property
def ready(self):
return self.state == self.READY
def created(self):
self._check_state()
return hasattr(self, 'state')


@property
def pending(self):
return self.state in [self.CREATED, self.STARTED, self.QUEUED]
def queued(self):
self._check_state()
return self.state != self.CREATED


@property
def started(self):
self._check_state()
return self.state not in [self.CREATED, self.QUEUED]


@property
def queued(self):
return self.state != self.CREATED
def passed(self):
self._check_state()
return self.state == self.PASSED


@property
def finished(self):
return not self.pending
def failed(self):
self._check_state()
return self.state == self.FAILED


@property
def passed(self):
return self.state == self.PASSED
def errored(self):
self._check_state()
return self.state == self.ERRORED


@property
def errored(self):
return self.state == self.ERRORED
def canceled(self):
self._check_state()
return self.state == self.CANCELED


@property
def failed(self):
return self.state == self.FAILED
def ready(self):
return self.state == self.READY


@property
def canceled(self):
return self.state == self.CANCELED
def pending(self):
self._check_state()
return self.state in [self.CREATED, self.STARTED, self.QUEUED]


@property
def running(self):
return self.state == self.STARTED


@property
def finished(self):
return not self.pending


@property
def successful(self):
return self.passed


@property
def unsuccessful(self):
return self.errored or self.failed or self.canceled


@property
def color(self):
self._check_state()
if self.passed or self.ready:
return self.GREEN

elif self.pending:
return self.YELLOW

elif self.unsuccessful:
return self.RED


@property
def green(self):
return self.color == self.GREEN


@property
def yellow(self):
return self.color == self.YELLOW


@property
def red(self):
return self.color == self.RED

def _check_state(self):
if self.state not in [
self.CANCELED,
self.CREATED,
self.ERRORED,
self.FAILED,
self.PASSED,
self.QUEUED,
self.READY,
self.STARTED,
]:
raise ValueError('unknown state %s for %s' % (self.state, self.__class__.__name__))
4 changes: 0 additions & 4 deletions travispy/entities/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ class Build(Restartable):
:ivar dict config:
Build config (secure values and ssh key removed). It comes from ``.travis.yml`` file.
:ivar str state:
Build state.
:ivar str started_at:
Time the build was started.
Expand All @@ -53,7 +50,6 @@ class Build(Restartable):
'pull_request_title',
'pull_request_number',
'config',
'state',
'started_at',
'finished_at',
'duration',
Expand Down
3 changes: 0 additions & 3 deletions travispy/entities/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ class Job(Restartable):
:ivar dict config:
Job config (secure values and ssh key removed). It comes from ``.travis.yml`` file.
:ivar str state:
Job state.
:ivar str started_at:
Time the job was started.
Expand Down
11 changes: 9 additions & 2 deletions travispy/entities/repo.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from ._entity import Entity
from ._stateful import Stateful



#===================================================================================================
# Repo
#===================================================================================================
class Repo(Entity):
class Repo(Stateful):
'''
:ivar str slug:
Repository slug.
Expand Down Expand Up @@ -51,3 +51,10 @@ class Repo(Entity):
'github_language',
'active',
]

@property
def state(self):
'''
This property must be overiden as soon as support to load "lazy" information is implemented.
'''
return self.CREATED

0 comments on commit 4975060

Please sign in to comment.