Merge lp:~salgado/offspring/object-factory into lp:offspring

Proposed by Guilherme Salgado
Status: Merged
Merged at revision: 89
Proposed branch: lp:~salgado/offspring/object-factory
Merge into: lp:offspring
Prerequisite: lp:~salgado/offspring/path-independence
Diff against target: 118 lines (+112/-0)
1 file modified
lib/offspring/web/queuemanager/tests/factory.py (+112/-0)
To merge this branch: bzr merge lp:~salgado/offspring/object-factory
Reviewer Review Type Date Requested Status
Kevin McDermott Approve
Offspring Hackers Pending
Review via email: mp+76737@code.launchpad.net

Description of the change

Create a new factory of (django) model objects to be used in tests

To post a comment you must log in.
Revision history for this message
Kevin McDermott (bigkevmcd) wrote :

#1

+ user = User.objects.create_user(
+ userid, self.get_unique_email_address(), password)
+ user.save()
+ return user

This could be simplified to

return User.objects.create_user(...)

The documentation for .create... "A convenience method for creating an object and saving it all in one step"

#2

You alternate between objects.create and direct instantiation throughout the code, any particular reason why?

#3

Can we aim for PEP8 compliance? i.e. "Function names should be lowercase, with words separated by underscores as necessary to improve readability."

def make_projectGrou should be def make_project_group

#4
You've added docstrings to some methods, but not others, can you add docstrings to each method, explaining what they do?

A headsup too...in my database-testing branch, I've removed offspring.config.config, I added get_configuration to offspring.config which returns a ConfigParser-type object, so...

    base_dir = config.master('result_directory')

will become...

    config = offspring.config.get_configuration()
    base_Dir = config.get('master', 'result_directory')

Of course, you can do...

   def __init__(...):
       ...
       self.config = offspring.config.get_configuration()

and then refer to self.config everywhere...

But, in this branch, prior to that getting landed, you can still change the config.master(...) reference to config.get('master', ...) which is what it's doing.

review: Needs Fixing
Revision history for this message
Guilherme Salgado (salgado) wrote :

On Tue, 2011-11-22 at 10:09 +0000, Kevin McDermott wrote:
> Review: Needs Fixing
>
> #1
>
> + user = User.objects.create_user(
> + userid, self.get_unique_email_address(), password)
> + user.save()
> + return user
>
> This could be simplified to
>
> return User.objects.create_user(...)
>
> The documentation for .create... "A convenience method for creating an
> object and saving it all in one step"

Oh, indeed; changed.

>
> #2
>
> You alternate between objects.create and direct instantiation
> throughout the code, any particular reason why?

Well, it's only for User that I use .objects.create_user(), and that's
because I think it's specific to UserManager. If I'm wrong I'd be happy
to use it for others as well.

> #3
>
> Can we aim for PEP8 compliance? i.e. "Function names should be
> lowercase, with words separated by underscores as necessary to improve
> readability."
>
> def make_projectGrou should be def make_project_group

That was an oversight when I renamed all methods to be PEP8 compliant.
I've fixed it.

>
> #4
> You've added docstrings to some methods, but not others, can you add
> docstrings to each method, explaining what they do?

TBH I didn't add any -- that one was copy-n-pasted from another
project. ;)

However, do you really think any of them need a docstring? I think
they're simple/obvious enough to not warrant one.

> A headsup too...in my database-testing branch, I've removed
> offspring.config.config, I added get_configuration to offspring.config
> which returns a ConfigParser-type object, so...
>
> base_dir = config.master('result_directory')
>
> will become...
>
> config = offspring.config.get_configuration()
> base_Dir = config.get('master', 'result_directory')
>
> Of course, you can do...
>
> def __init__(...):
> ...
> self.config = offspring.config.get_configuration()
>
> and then refer to self.config everywhere...
>
> But, in this branch, prior to that getting landed, you can still
> change the config.master(...) reference to config.get('master', ...)
> which is what it's doing.

But this branch doesn't change any code using that -- it's the previous
one (path-independence) that does. Maybe the diff you reviewed included
the changes from path-independence as well?

lp:~salgado/offspring/object-factory updated
41. By Guilherme Salgado

PEP8 compliance and do not call .save() on the return value of User.objects.create_user() as that's not necessary

Revision history for this message
Kevin McDermott (bigkevmcd) wrote :

> > #2
> >
> > You alternate between objects.create and direct instantiation
> > throughout the code, any particular reason why?

Yeah, but all the other managers can create, saving you the .save() so...

+ def make_build_request(self, project=None):
+ if project is None:
+ project = self.make_project()
+ project.save()
+ request = BuildRequest(project=project)
+ request.save()
+ return request

could become...

    def make_build_request(self, project=None):
        if project is None:
            project = self.make_project()
        return BuildRequest.objects.create(project=project)

> > #4
> > You've added docstrings to some methods, but not others, can you add
> > docstrings to each method, explaining what they do?

They can have a simple one, for example...
"""
Create a build_request, if no project is given, create a project and associate the build with the newly created project.
"""

Sorry, the bit about config was just a headsup, it shouldn't really have gone in there...

lp:~salgado/offspring/object-factory updated
42. By Guilherme Salgado

Add docstrings and use .objects.create() to avoid a save() call

Revision history for this message
Guilherme Salgado (salgado) wrote :

On Tue, 2011-11-22 at 17:18 +0000, Kevin McDermott wrote:
> > > #2
> > >
> > > You alternate between objects.create and direct instantiation
> > > throughout the code, any particular reason why?
>
> Yeah, but all the other managers can create, saving you the .save() so.

Oh, cool, I've changed them all, but I couldn't find
ModelManager.create() in the docs. Care to point me where you found
them?

> ..
>
> + def make_build_request(self, project=None):
> + if project is None:
> + project = self.make_project()
> + project.save()
> + request = BuildRequest(project=project)
> + request.save()
> + return request
>
> could become...
>
> def make_build_request(self, project=None):
> if project is None:
> project = self.make_project()
> return BuildRequest.objects.create(project=project)

Yep, much simpler.

>
> > > #4
> > > You've added docstrings to some methods, but not others, can you add
> > > docstrings to each method, explaining what they do?
>
> They can have a simple one, for example...
> """
> Create a build_request, if no project is given, create a project and associate the build with the newly created project.
> """

To me this feels like I'm repeating myself as it's not saying anything
that's not easily inferred from the method's signature, but I've added
them. :)

Revision history for this message
Kevin McDermott (bigkevmcd) wrote :

> Oh, cool, I've changed them all, but I couldn't find
> ModelManager.create() in the docs. Care to point me where you found
> them?

https://docs.djangoproject.com/en/1.3/ref/models/querysets/#create :-)

>
> To me this feels like I'm repeating myself as it's not saying anything
> that's not easily inferred from the method's signature, but I've added
> them. :)

Thanks :-)

Looks good to me, +1

Revision history for this message
Kevin McDermott (bigkevmcd) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'lib/offspring/web/queuemanager/tests'
2=== added file 'lib/offspring/web/queuemanager/tests/__init__.py'
3=== added file 'lib/offspring/web/queuemanager/tests/factory.py'
4--- lib/offspring/web/queuemanager/tests/factory.py 1970-01-01 00:00:00 +0000
5+++ lib/offspring/web/queuemanager/tests/factory.py 2011-11-22 18:30:29 +0000
6@@ -0,0 +1,112 @@
7+from itertools import count
8+
9+from django.contrib.auth.models import User
10+
11+from offspring.web.queuemanager.models import (
12+ BuildRequest,
13+ BuildResult,
14+ Lexbuilder,
15+ ProjectGroup,
16+ Project,
17+ Release)
18+
19+
20+class ObjectFactory(object):
21+
22+ def __init__(self):
23+ self.counter = count()
24+
25+ def get_unique_email_address(self):
26+ """Return an email address unique to this factory instance."""
27+ return "%s@example.com" % self.get_unique_string('email')
28+
29+ def get_unique_string(self, prefix=None):
30+ """Return a string unique to this factory instance.
31+
32+ :param prefix: Used as a prefix for the unique string. If unspecified,
33+ defaults to 'generic-string'.
34+ """
35+ if prefix is None:
36+ prefix = "generic-string"
37+ string = "%s%s" % (prefix, self.get_unique_integer())
38+ return string.lower()
39+
40+ def get_unique_integer(self):
41+ """Return an integer unique to this factory instance."""
42+ return self.counter.next()
43+
44+ def make_user(self):
45+ """Create a new User."""
46+ userid = password = self.get_unique_string()
47+ return User.objects.create_user(
48+ userid, self.get_unique_email_address(), password)
49+
50+ def make_project(self, name=None, title=None):
51+ """
52+ Create a Project with the given name and title. If any of those is not
53+ given we use an arbitrary value.
54+ """
55+ if name is None:
56+ name = self.get_unique_string()
57+ if title is None:
58+ title = self.get_unique_string()
59+ return Project.objects.create(name=name, title=title)
60+
61+ def make_project_group(self, name=None, title=None):
62+ """
63+ Create a ProjectGroup with the given name and title. If any of those
64+ is not given we use an arbitrary value.
65+ """
66+ if name is None:
67+ name = self.get_unique_string()
68+ if title is None:
69+ title = self.get_unique_string()
70+ return ProjectGroup.objects.create(name=name, title=title)
71+
72+ def make_build_result(self, project=None):
73+ """
74+ Create a BuildResult with the given project or a newly created one if
75+ none is given.
76+ """
77+ if project is None:
78+ project = self.make_project()
79+ return BuildResult.objects.create(project=project)
80+
81+ def make_release(self, build=None, name=None, creator=None):
82+ """
83+ Create a Release with the given build, name and creator. If any
84+ of those is not given we use an arbitrary value.
85+ """
86+ if build is None:
87+ build = self.make_build_result()
88+ if name is None:
89+ name = self.get_unique_string()
90+ if creator is None:
91+ creator = self.make_user()
92+ return Release.objects.create(build=build, name=name, creator=creator)
93+
94+ def make_lexbuilder(self, name=None, uri=None, current_job=None):
95+ """
96+ Create a Lexbuilder with the given name, uri and current_job. If any
97+ of those is not given we use an arbitrary value.
98+ """
99+ if name is None:
100+ name = self.get_unique_string()
101+ if uri is None:
102+ uri = 'htt://example.com/%s' % name
103+ if current_job is None:
104+ current_job = self.make_build_result()
105+ return Lexbuilder.objects.create(
106+ name=name, uri=uri, current_job=current_job)
107+
108+ def make_build_request(self, project=None):
109+ """
110+ Create a BuildRequest, if no project is given, create a project and
111+ associate the build with the newly created project.
112+ """
113+ if project is None:
114+ project = self.make_project()
115+ return BuildRequest.objects.create(project=project)
116+
117+
118+factory = ObjectFactory()

Subscribers

People subscribed via source and target branches