Transferring value of variable from one unrelated class to another - oop

If I want to create a program using Python2.7 where:
1) There are three classes, namely Tagging, Commenting, and Posting
2) The self.content for both Tagging and Commenting classes will be sent to the self.compact of class Posting
class Tagging: # Handles Tagging - Create new Tags
def __init__(self):
self.content = []
self.initialTag = ""
def doTag(self): #Tag people
self.initialTag = raw_input("Name to Tag: ")
self.content.append(self.initialTag)
#Tagging can only be done if the user created new post.
class Commenting: #Handles Commenting - Create new Comments
def __init__(self):
self.content = []
self.initialComment = ""
def doComment(self): #Commenting on Posts
self.initialComment = raw_input("Comment: ")
self.content.append(self.initialComment)
#Commenting can only be done on Posts. No Post means no Comment. (Same goes to Tags)
class Posting: #Handles Posting - Create new Posts
def __init__(self):
self.content = [] #Content of the post
self.initialPost = ""
self.compact = [] #Post that contains the Post, Comments, and Tags
#How do I do this?
def doPost(self):
self.initialPost = raw_input("Post: ")
self.content.append(self.initialPost)
I tried inheriting class Posting to both class Tagging and class Commenting but I think using Inheritance just for one single variable of class Posting is illogical.
Can anyone suggest me a better way?
And additional question: Are the class Tagging and class Commenting having Aggregation relationship to class Posting? Or is it an Association relationship? (word definition by UML)

How about this, just example code in "__ main __" part:
class Tagging: # Handles Tagging - Create new Tags
def __init__(self):
self.content = []
self.initialTag = ""
def doTag(self): #Tag people
self.initialTag = raw_input("Name to Tag: ")
self.content.append(self.initialTag)
#Tagging can only be done if the user created new post.
class Commenting: #Handles Commenting - Create new Comments
def __init__(self):
self.content = []
self.initialComment = ""
def doComment(self): #Commenting on Posts
self.initialComment = raw_input("Comment: ")
self.content.append(self.initialComment)
#Commenting can only be done on Posts. No Post means no Comment. (Same goes to Tags)
class Posting: #Handles Posting - Create new Posts
def __init__(self, TaggingContent, CommentingContent):
self.content = [] #Content of the post
self.initialPost = ""
self.compact = TaggingContent + CommentingContent #Post that contains the Post, Comments, and Tags
#How do I do this?
def doPost(self):
self.initialPost = raw_input("Post: ")
self.content.append(self.initialPost)
if __name__ == "__main__":
T = Tagging()
C = Commenting()
##Do stuff here with tagging and commenting....
P = Posting(T.content, C.content)
#Do stuff with posting
That way you have the content from Tagging and Commenting into compact from Posting, or am I wrong about what you need?

If you want to ensure in OOP that a set of classes provides obeys a certain contract you normally define an interface.
Python does not provide interfaces directly, but instead it's common to use duck-typeing by the use of something like isinstance or hasattr, which means, that if your object has a content-property use it, if not, raise an error.
Another possiblity to emulate interfaces is available since Python 2.6 by means of Abstract Base Classes
Hope this helps.

Related

Django returns empty QuerySet in the tests

I'm trying to make a test for this view:
def author_detail(request, pk):
author = get_object_or_404(Author, pk=pk)
blog = author.blog_set.all()
paginator = Paginator(blog, 1)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
context = {
'author': author,
'page_obj': page_obj,
}
return render(request, 'blog/author_detail.html', context=context)
The view is working normally. My problem is when I'm going to try to test this view. Here my test:
class AuthorDetailViewTest(TestCase):
def setUp(self):
user = User.objects.create(username='user01', password='123456')
self.author_instance = Author.objects.create(
user=user, date_of_birth='1998-09-08', bio='I am user01')
topic = Topic.objects.create(name='Testing')
Blog.objects.create(title='My blog', content="It's my blog")
Blog.author = self.author_instance
Blog.topic = topic
# The author.blog_set.all() are returning an empty QuerySet
# This problem are only happening in the tests, not in the view
def test_pagination_first_page(self):
response = self.client.get(
reverse('author-detail', kwargs={'pk':self.author_instance.pk}))
self.assertEqual(len(response.context['page_obj']), 1)
The result are:
FAIL: test_pagination_first_page (blog.tests.test_views.AuthorDetailViewTest)
-------------------------------------------------------------------
Traceback (most recent call last):
File "/home/carlos/problem/venv_01/the_blog/blog/tests/test_views.py", line 189,in test_pagination_first_page
self.assertEqual(len(response.context['page_obj']), 1)
AssertionError: 0 != 1
----------------------------------------------------------------------
The len(response.context['page_obj']) is equal 0. It should be at least 1, because I created one Blog object. When I print the QuerySet of author.blog_set.all(), the returned QuerySet are empty (<QuerySet []>). I think that the problem is in the creation of the Blog model, because the author and topic fields are ManyToManyField.
As I mentioned before, my problem is in the test, not in the view. The view is working normally.
The last 3 lines of the following code snippet have some issues:
def setUp(self):
user = User.objects.create(username='user01', password='123456')
self.author_instance = Author.objects.create(
user=user, date_of_birth='1998-09-08', bio='I am user01')
topic = Topic.objects.create(name='Testing')
Blog.objects.create(title='My blog', content="It's my blog")
Blog.author = self.author_instance
Blog.topic = topic
The blog object is created but never returned/fetched
Blog model is being used to connect author and topic. Instead, the blog object should be used.
Author and Topic are M2M on Blog. The new objects should be added via add method. See How to add data into ManyToMany field? for additional context.
Solution:
def setUp(self):
user = User.objects.create(username='user01', password='123456')
author = Author.objects.create(
user=user, date_of_birth='1998-09-08', bio='I am user01')
blog = Blog.objects.create(
title='My blog', content="It's my blog")
blog.author.add(author)
blog.topic.add(topic)
It worked.

How to extract the [Documentation] text from Robot framework test case

I am trying to extract the content of the [Documentation] section as a string for comparision with other part in a Python script.
I was told to use Robot framework API https://robot-framework.readthedocs.io/en/stable/
to extract but I have no idea how.
However, I am required to work with version 3.1.2
Example:
*** Test Cases ***
ATC Verify that Sensor Battery can enable and disable manufacturing mode
[Documentation] E1: This is the description of the test 1
... E2: This is the description of the test 2
[Tags] E1 TRACE{Trace_of_E1}
... E2 TRACE{Trace_of_E2}
Extract the string as
E1: This is the description of the test 1
E2: This is the description of the test 2
Have a look at these examples. I did something similar to generate testplans descritio. I tried to adapt my code to your requirements and this could maybe work for you.
import os
import re
from robot.api.parsing import (
get_model, get_tokens, Documentation, EmptyLine, KeywordCall,
ModelVisitor, Token
)
class RobotParser(ModelVisitor):
def __init__(self):
# Create object with remarkup_text to store formated documentation
self.text = ''
def get_text(self):
return self.text
def visit_TestCase(self, node):
# The matched `TestCase` node is a block with `header` and
# `body` attributes. `header` is a statement with familiar
# `get_token` and `get_value` methods for getting certain
# tokens or their value.
for keyword in node.body:
# skip empty lines
if keyword.get_value(Token.DOCUMENTATION) == None:
continue
self.text += keyword.get_value(Token.ARGUMENT)
def visit_Documentation(self,node):
# The matched "Documentation" node with value
self.remarkup_text += node.value + self.new_line
def visit_File(self, node):
# Call `generic_visit` to visit also child nodes.
return self.generic_visit(node)
if __name__ == "__main__":
path = "../tests"
for filename in os.listdir(path):
if re.match(".*\.robot", filename):
model = get_model(os.path.join(path, filename))
robot_parser = RobotParser()
robot_parser.visit(model)
text=robot_parser._text()
The code marked as best answer didn't quite work for me and has a lot of redundancy but it inspired me enough to get into the parsing and write it in a much readable and efficient way that actually works as is. You just have to have your own way of generating & iterating through filesystem where you call the get_robot_metadata(filepath) function.
from robot.api.parsing import (get_model, ModelVisitor, Token)
class RobotParser(ModelVisitor):
def __init__(self):
self.testcases = {}
def visit_TestCase(self, node):
testcasename = (node.header.name)
self.testcases[testcasename] = {}
for section in node.body:
if section.get_value(Token.DOCUMENTATION) != None:
documentation = section.value
self.testcases[testcasename]['Documentation'] = documentation
elif section.get_value(Token.TAGS) != None:
tags = section.values
self.testcases[testcasename]['Tags'] = tags
def get_testcases(self):
return self.testcases
def get_robot_metadata(filepath):
if filepath.endswith('.robot'):
robot_parser = RobotParser()
model = get_model(filepath)
robot_parser.visit(model)
metadata = robot_parser.get_testcases()
return metadata
This function will be able to extract the [Documentation] section from the testcase:
def documentation_extractor(testcase):
documentation = []
for setting in testcase.settings:
if len(setting) > 2 and setting[1].lower() == "[documentation]":
for doc in setting[2:]:
if doc.startswith("#"):
# the start of a comment, so skip rest of the line
break
documentation.append(doc)
break
return "\n".join(documentation)

How to save formwizard POST request to a database

How do I save the form_data to a database?
forms.py
class ContactWizard(SessionWizardView):
template_name ='fitness/general.html'
def done(self, form_list, **kwargs):
form_data = process_form_data(form_list)
return render_to_response('fitness/general2.html', {'form_data': form_data})
def process_form_data(form_list):
form_data = [form.cleaned_data for form in form_list]
return form_data
I have encountered this problem before while doing an online resume builder
def done(self, form_list , **kwargs):
form_data = [
form for form in form_list
]
first_form = form_data[0]
first_instance = first_form.save(commit = False)
#TODO: add other stuff before saving
first_instance.save()
I believe this code may help you. It does nothing extra, as form_data contains all the forms, you can get them by indexing. Of course you can use loop but usually different forms may require different procedures.

Custom ConnectionField in graphene

I'm not understanding how to use custom fields in a ConnectionField in graphene. I have something like:
class ShipConnection(Connection):
extra = String()
class Meta:
node = Ship
SHIPS = ['Tug boat', 'Row boat', 'Canoe']
class Query(AbstractType):
ships = relay.ConnectionField(ShipConnection)
def resolve_ships(self, args, context, info):
return ShipConnection(
extra='Some extra text',
edges=???
)
Normally, you'd say:
def resolve_ships(self, args, context, info):
return SHIPS
but how do you return something in extra and return a list?
The answer turns out to be to use an undocumented class method of graphene's ConnectionField class, called resolve_connection. The following works:
def resolve_ships(self, args, context, info):
field = relay.ConnectionField.resolve_connection(
ShipConnection,
args,
SHIPS
)
field.extra = 'Whatever'
return field
The proper way to do this is exactly explained here.
class Ship(graphene.ObjectType):
ship_type = String()
def resolve_ship_type(self, info):
return self.ship_type
class Meta:
interfaces = (Node,)
class ShipConnection(Connection):
total_count = Int() # i've found count on connections very useful!
def resolve_total_count(self, info):
return get_count_of_all_ships()
class Meta:
node = Ship
class Edge:
other = String()
def resolve_other(self, info):
return "This is other: " + self.node.other
class Query(graphene.ObjectType):
ships = relay.ConnectionField(ShipConnection)
def resolve_ships(self, info):
return get_list_of_ships_from_database_or_something_idk_its_your_implmentation()
schema = graphene.Schema(query=Query)
I don't know if this is recommended, but the resolve_total_count method can also be implemented as:
def resolve_total_count(self, info):
return len(self.iterable)
I don't know if the iterable property is documented anywhere, but I was able to find it while investigating the Connection class

Test fails in tests.py but succeeds in python shell

I'm a newbee to python and django and I can't figure out what I'm doing wrong here.
I have a Site object:
class Site (models.Model):
domain = models.CharField(max_length=30)
support_status = models.CharField(max_length=20, choices= SITE_SUPPORTED_STATUS, blank=False)
requests = models.IntegerField()
objects = SiteManager()
def __unicode__(self):
return u'%s %s' % (self.domain, self.support_status)
And a SiteManager object
class SiteManager(models.Manager):
def supported_site_counts(self):
i = self.filter(support_status__iexact="SUPPORTED").count()
return i
From the console, the method "supported_site_counts()" works just fine
>>(InteractiveConsole)
>>> from bookmark.models import Site, SiteManager
>>> Site.objects.supported_site_counts()
>>>>2012-05-18 18:09:20,027 DEBUG (0.001) SELECT COUNT(*) FROM "bookmark_site" WHERE
>>>>"bookmark_site"."support_status" LIKE SUPPORTED ESCAPE '\' ; args=(u'SUPPORTED',)
>>>>2012-05-18 18:09:20,028 DEBUG Got 1 supported site
>>>>1
But when it's called from a testcase, the count returns as 0
class SiteManagerTest(unittest.TestCase):
def test_supported_site_counts(self):
self.x = False
self.count = Site.objects.supported_site_counts()
logging.debug(self.count)
This is probably because the tests will set up a database separate from your development database to run the tests in. You will need to put testing data in to the testing database, either programmatically or using fixtures.