pep8
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from fs.osfs import OSFS
|
from fs.osfs import OSFS
|
||||||
from nose.tools import assert_equals, assert_true
|
|
||||||
from path import path
|
from path import path
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
import shutil
|
import shutil
|
||||||
@@ -22,7 +21,7 @@ def strip_filenames(descriptor):
|
|||||||
"""
|
"""
|
||||||
Recursively strips 'filename' from all children's definitions.
|
Recursively strips 'filename' from all children's definitions.
|
||||||
"""
|
"""
|
||||||
print "strip filename from {desc}".format(desc=descriptor.location.url())
|
print("strip filename from {desc}".format(desc=descriptor.location.url()))
|
||||||
descriptor._model_data.pop('filename', None)
|
descriptor._model_data.pop('filename', None)
|
||||||
|
|
||||||
if hasattr(descriptor, 'xml_attributes'):
|
if hasattr(descriptor, 'xml_attributes'):
|
||||||
@@ -41,12 +40,12 @@ class RoundTripTestCase(unittest.TestCase):
|
|||||||
'''
|
'''
|
||||||
def check_export_roundtrip(self, data_dir, course_dir):
|
def check_export_roundtrip(self, data_dir, course_dir):
|
||||||
root_dir = path(self.temp_dir)
|
root_dir = path(self.temp_dir)
|
||||||
print "Copying test course to temp dir {0}".format(root_dir)
|
print("Copying test course to temp dir {0}".format(root_dir))
|
||||||
|
|
||||||
data_dir = path(data_dir)
|
data_dir = path(data_dir)
|
||||||
shutil.copytree(data_dir / course_dir, root_dir / course_dir)
|
shutil.copytree(data_dir / course_dir, root_dir / course_dir)
|
||||||
|
|
||||||
print "Starting import"
|
print("Starting import")
|
||||||
initial_import = XMLModuleStore(root_dir, course_dirs=[course_dir])
|
initial_import = XMLModuleStore(root_dir, course_dirs=[course_dir])
|
||||||
|
|
||||||
courses = initial_import.get_courses()
|
courses = initial_import.get_courses()
|
||||||
@@ -55,7 +54,7 @@ class RoundTripTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
# export to the same directory--that way things like the custom_tags/ folder
|
# export to the same directory--that way things like the custom_tags/ folder
|
||||||
# will still be there.
|
# will still be there.
|
||||||
print "Starting export"
|
print("Starting export")
|
||||||
fs = OSFS(root_dir)
|
fs = OSFS(root_dir)
|
||||||
export_fs = fs.makeopendir(course_dir)
|
export_fs = fs.makeopendir(course_dir)
|
||||||
|
|
||||||
@@ -63,14 +62,14 @@ class RoundTripTestCase(unittest.TestCase):
|
|||||||
with export_fs.open('course.xml', 'w') as course_xml:
|
with export_fs.open('course.xml', 'w') as course_xml:
|
||||||
course_xml.write(xml)
|
course_xml.write(xml)
|
||||||
|
|
||||||
print "Starting second import"
|
print("Starting second import")
|
||||||
second_import = XMLModuleStore(root_dir, course_dirs=[course_dir])
|
second_import = XMLModuleStore(root_dir, course_dirs=[course_dir])
|
||||||
|
|
||||||
courses2 = second_import.get_courses()
|
courses2 = second_import.get_courses()
|
||||||
self.assertEquals(len(courses2), 1)
|
self.assertEquals(len(courses2), 1)
|
||||||
exported_course = courses2[0]
|
exported_course = courses2[0]
|
||||||
|
|
||||||
print "Checking course equality"
|
print("Checking course equality")
|
||||||
|
|
||||||
# HACK: filenames change when changing file formats
|
# HACK: filenames change when changing file formats
|
||||||
# during imports from old-style courses. Ignore them.
|
# during imports from old-style courses. Ignore them.
|
||||||
@@ -81,16 +80,18 @@ class RoundTripTestCase(unittest.TestCase):
|
|||||||
self.assertEquals(initial_course.id, exported_course.id)
|
self.assertEquals(initial_course.id, exported_course.id)
|
||||||
course_id = initial_course.id
|
course_id = initial_course.id
|
||||||
|
|
||||||
print "Checking key equality"
|
print("Checking key equality")
|
||||||
self.assertEquals(sorted(initial_import.modules[course_id].keys()),
|
self.assertEquals(sorted(initial_import.modules[course_id].keys()),
|
||||||
sorted(second_import.modules[course_id].keys()))
|
sorted(second_import.modules[course_id].keys()))
|
||||||
|
|
||||||
print "Checking module equality"
|
print("Checking module equality")
|
||||||
for location in initial_import.modules[course_id].keys():
|
for location in initial_import.modules[course_id].keys():
|
||||||
print "Checking", location
|
print("Checking", location)
|
||||||
if location.category == 'html':
|
if location.category == 'html':
|
||||||
print ("Skipping html modules--they can't import in"
|
print(
|
||||||
" final form without writing files...")
|
"Skipping html modules--they can't import in"
|
||||||
|
" final form without writing files..."
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
self.assertEquals(initial_import.modules[course_id][location],
|
self.assertEquals(initial_import.modules[course_id][location],
|
||||||
second_import.modules[course_id][location])
|
second_import.modules[course_id][location])
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class BaseCourseTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
def get_course(self, name):
|
def get_course(self, name):
|
||||||
"""Get a test course by directory name. If there's more than one, error."""
|
"""Get a test course by directory name. If there's more than one, error."""
|
||||||
print "Importing {0}".format(name)
|
print("Importing {0}".format(name))
|
||||||
|
|
||||||
modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name])
|
modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name])
|
||||||
courses = modulestore.get_courses()
|
courses = modulestore.get_courses()
|
||||||
@@ -145,7 +145,7 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
descriptor = system.process_xml(start_xml)
|
descriptor = system.process_xml(start_xml)
|
||||||
compute_inherited_metadata(descriptor)
|
compute_inherited_metadata(descriptor)
|
||||||
|
|
||||||
print descriptor, descriptor._model_data
|
print(descriptor, descriptor._model_data)
|
||||||
self.assertEqual(descriptor.lms.due, Date().from_json(v))
|
self.assertEqual(descriptor.lms.due, Date().from_json(v))
|
||||||
|
|
||||||
# Check that the child inherits due correctly
|
# Check that the child inherits due correctly
|
||||||
@@ -161,7 +161,7 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
exported_xml = descriptor.export_to_xml(resource_fs)
|
exported_xml = descriptor.export_to_xml(resource_fs)
|
||||||
|
|
||||||
# Check that the exported xml is just a pointer
|
# Check that the exported xml is just a pointer
|
||||||
print "Exported xml:", exported_xml
|
print("Exported xml:", exported_xml)
|
||||||
pointer = etree.fromstring(exported_xml)
|
pointer = etree.fromstring(exported_xml)
|
||||||
self.assertTrue(is_pointer_tag(pointer))
|
self.assertTrue(is_pointer_tag(pointer))
|
||||||
# but it's a special case course pointer
|
# but it's a special case course pointer
|
||||||
@@ -255,29 +255,29 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
|
|
||||||
no = ["""<html url_name="blah" also="this"/>""",
|
no = ["""<html url_name="blah" also="this"/>""",
|
||||||
"""<html url_name="blah">some text</html>""",
|
"""<html url_name="blah">some text</html>""",
|
||||||
"""<problem url_name="blah"><sub>tree</sub></problem>""",
|
"""<problem url_name="blah"><sub>tree</sub></problem>""",
|
||||||
"""<course org="HogwartsX" course="Mathemagics" url_name="3.14159">
|
"""<course org="HogwartsX" course="Mathemagics" url_name="3.14159">
|
||||||
<chapter>3</chapter>
|
<chapter>3</chapter>
|
||||||
</course>
|
</course>
|
||||||
"""]
|
"""]
|
||||||
|
|
||||||
for xml_str in yes:
|
for xml_str in yes:
|
||||||
print "should be True for {0}".format(xml_str)
|
print("should be True for {0}".format(xml_str))
|
||||||
self.assertTrue(is_pointer_tag(etree.fromstring(xml_str)))
|
self.assertTrue(is_pointer_tag(etree.fromstring(xml_str)))
|
||||||
|
|
||||||
for xml_str in no:
|
for xml_str in no:
|
||||||
print "should be False for {0}".format(xml_str)
|
print("should be False for {0}".format(xml_str))
|
||||||
self.assertFalse(is_pointer_tag(etree.fromstring(xml_str)))
|
self.assertFalse(is_pointer_tag(etree.fromstring(xml_str)))
|
||||||
|
|
||||||
def test_metadata_inherit(self):
|
def test_metadata_inherit(self):
|
||||||
"""Make sure that metadata is inherited properly"""
|
"""Make sure that metadata is inherited properly"""
|
||||||
|
|
||||||
print "Starting import"
|
print("Starting import")
|
||||||
course = self.get_course('toy')
|
course = self.get_course('toy')
|
||||||
|
|
||||||
def check_for_key(key, node):
|
def check_for_key(key, node):
|
||||||
"recursive check for presence of key"
|
"recursive check for presence of key"
|
||||||
print "Checking {0}".format(node.location.url())
|
print("Checking {0}".format(node.location.url()))
|
||||||
self.assertTrue(key in node._model_data)
|
self.assertTrue(key in node._model_data)
|
||||||
for c in node.get_children():
|
for c in node.get_children():
|
||||||
check_for_key(key, c)
|
check_for_key(key, c)
|
||||||
@@ -322,14 +322,14 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
|
|
||||||
location = Location(["i4x", "edX", "toy", "video", "Welcome"])
|
location = Location(["i4x", "edX", "toy", "video", "Welcome"])
|
||||||
toy_video = modulestore.get_instance(toy_id, location)
|
toy_video = modulestore.get_instance(toy_id, location)
|
||||||
two_toy_video = modulestore.get_instance(two_toy_id, location)
|
two_toy_video = modulestore.get_instance(two_toy_id, location)
|
||||||
self.assertEqual(etree.fromstring(toy_video.data).get('youtube'), "1.0:p2Q6BrNhdh8")
|
self.assertEqual(etree.fromstring(toy_video.data).get('youtube'), "1.0:p2Q6BrNhdh8")
|
||||||
self.assertEqual(etree.fromstring(two_toy_video.data).get('youtube'), "1.0:p2Q6BrNhdh9")
|
self.assertEqual(etree.fromstring(two_toy_video.data).get('youtube'), "1.0:p2Q6BrNhdh9")
|
||||||
|
|
||||||
def test_colon_in_url_name(self):
|
def test_colon_in_url_name(self):
|
||||||
"""Ensure that colons in url_names convert to file paths properly"""
|
"""Ensure that colons in url_names convert to file paths properly"""
|
||||||
|
|
||||||
print "Starting import"
|
print("Starting import")
|
||||||
# Not using get_courses because we need the modulestore object too afterward
|
# Not using get_courses because we need the modulestore object too afterward
|
||||||
modulestore = XMLModuleStore(DATA_DIR, course_dirs=['toy'])
|
modulestore = XMLModuleStore(DATA_DIR, course_dirs=['toy'])
|
||||||
courses = modulestore.get_courses()
|
courses = modulestore.get_courses()
|
||||||
@@ -337,10 +337,10 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
course = courses[0]
|
course = courses[0]
|
||||||
course_id = course.id
|
course_id = course.id
|
||||||
|
|
||||||
print "course errors:"
|
print("course errors:")
|
||||||
for (msg, err) in modulestore.get_item_errors(course.location):
|
for (msg, err) in modulestore.get_item_errors(course.location):
|
||||||
print msg
|
print(msg)
|
||||||
print err
|
print(err)
|
||||||
|
|
||||||
chapters = course.get_children()
|
chapters = course.get_children()
|
||||||
self.assertEquals(len(chapters), 2)
|
self.assertEquals(len(chapters), 2)
|
||||||
@@ -348,12 +348,12 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
ch2 = chapters[1]
|
ch2 = chapters[1]
|
||||||
self.assertEquals(ch2.url_name, "secret:magic")
|
self.assertEquals(ch2.url_name, "secret:magic")
|
||||||
|
|
||||||
print "Ch2 location: ", ch2.location
|
print("Ch2 location: ", ch2.location)
|
||||||
|
|
||||||
also_ch2 = modulestore.get_instance(course_id, ch2.location)
|
also_ch2 = modulestore.get_instance(course_id, ch2.location)
|
||||||
self.assertEquals(ch2, also_ch2)
|
self.assertEquals(ch2, also_ch2)
|
||||||
|
|
||||||
print "making sure html loaded"
|
print("making sure html loaded")
|
||||||
cloc = course.location
|
cloc = course.location
|
||||||
loc = Location(cloc.tag, cloc.org, cloc.course, 'html', 'secret:toylab')
|
loc = Location(cloc.tag, cloc.org, cloc.course, 'html', 'secret:toylab')
|
||||||
html = modulestore.get_instance(course_id, loc)
|
html = modulestore.get_instance(course_id, loc)
|
||||||
@@ -378,7 +378,7 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
for i in (2, 3):
|
for i in (2, 3):
|
||||||
video = sections[i]
|
video = sections[i]
|
||||||
# Name should be 'video_{hash}'
|
# Name should be 'video_{hash}'
|
||||||
print "video {0} url_name: {1}".format(i, video.url_name)
|
print("video {0} url_name: {1}".format(i, video.url_name))
|
||||||
|
|
||||||
self.assertEqual(len(video.url_name), len('video_') + 12)
|
self.assertEqual(len(video.url_name), len('video_') + 12)
|
||||||
|
|
||||||
@@ -393,8 +393,10 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
self.assertEqual(len(sections), 1)
|
self.assertEqual(len(sections), 1)
|
||||||
|
|
||||||
location = course.location
|
location = course.location
|
||||||
location = Location(location.tag, location.org, location.course,
|
location = Location(
|
||||||
'sequential', 'Problem_Demos')
|
location.tag, location.org, location.course,
|
||||||
|
'sequential', 'Problem_Demos'
|
||||||
|
)
|
||||||
module = modulestore.get_instance(course.id, location)
|
module = modulestore.get_instance(course.id, location)
|
||||||
self.assertEqual(len(module.children), 2)
|
self.assertEqual(len(module.children), 2)
|
||||||
|
|
||||||
@@ -406,7 +408,6 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
|
|
||||||
self.assertRaises(etree.XMLSyntaxError, system.process_xml, bad_xml)
|
self.assertRaises(etree.XMLSyntaxError, system.process_xml, bad_xml)
|
||||||
|
|
||||||
|
|
||||||
def test_graphicslidertool_import(self):
|
def test_graphicslidertool_import(self):
|
||||||
'''
|
'''
|
||||||
Check to see if definition_from_xml in gst_module.py
|
Check to see if definition_from_xml in gst_module.py
|
||||||
@@ -434,8 +435,10 @@ class ImportTestCase(BaseCourseTestCase):
|
|||||||
self.assertEqual(len(sections), 1)
|
self.assertEqual(len(sections), 1)
|
||||||
|
|
||||||
location = course.location
|
location = course.location
|
||||||
location = Location(location.tag, location.org, location.course,
|
location = Location(
|
||||||
'sequential', 'Problem_Demos')
|
location.tag, location.org, location.course,
|
||||||
|
'sequential', 'Problem_Demos'
|
||||||
|
)
|
||||||
module = modulestore.get_instance(course.id, location)
|
module = modulestore.get_instance(course.id, location)
|
||||||
self.assertEqual(len(module.children), 1)
|
self.assertEqual(len(module.children), 1)
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
import json
|
import json
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from django.http import QueryDict
|
|
||||||
|
|
||||||
from xmodule.poll_module import PollDescriptor
|
from xmodule.poll_module import PollDescriptor
|
||||||
from xmodule.conditional_module import ConditionalDescriptor
|
from xmodule.conditional_module import ConditionalDescriptor
|
||||||
from xmodule.word_cloud_module import WordCloudDescriptor
|
from xmodule.word_cloud_module import WordCloudDescriptor
|
||||||
@@ -16,15 +14,18 @@ class LogicTest(unittest.TestCase):
|
|||||||
raw_model_data = {}
|
raw_model_data = {}
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
class EmptyClass: pass
|
class EmptyClass:
|
||||||
|
pass
|
||||||
|
|
||||||
self.system = None
|
self.system = None
|
||||||
self.location = None
|
self.location = None
|
||||||
self.descriptor = EmptyClass()
|
self.descriptor = EmptyClass()
|
||||||
|
|
||||||
self.xmodule_class = self.descriptor_class.module_class
|
self.xmodule_class = self.descriptor_class.module_class
|
||||||
self.xmodule = self.xmodule_class(self.system, self.location,
|
self.xmodule = self.xmodule_class(
|
||||||
self.descriptor, self.raw_model_data)
|
self.system, self.location,
|
||||||
|
self.descriptor, self.raw_model_data
|
||||||
|
)
|
||||||
|
|
||||||
def ajax_request(self, dispatch, get):
|
def ajax_request(self, dispatch, get):
|
||||||
return json.loads(self.xmodule.handle_ajax(dispatch, get))
|
return json.loads(self.xmodule.handle_ajax(dispatch, get))
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ Stunent can change his answer.
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from pkg_resources import resource_string
|
from pkg_resources import resource_string
|
||||||
@@ -30,21 +29,22 @@ class WordCloudFields(object):
|
|||||||
num_top_words = Integer(help="Number of max words, which will be displayed.", scope=Scope.settings, default=250)
|
num_top_words = Integer(help="Number of max words, which will be displayed.", scope=Scope.settings, default=250)
|
||||||
|
|
||||||
submitted = Boolean(help="Whether this student has posted words to the cloud", scope=Scope.user_state, default=False)
|
submitted = Boolean(help="Whether this student has posted words to the cloud", scope=Scope.user_state, default=False)
|
||||||
student_words= List(help="Student answer", scope=Scope.user_state, default=[])
|
student_words = List(help="Student answer", scope=Scope.user_state, default=[])
|
||||||
|
|
||||||
all_words = Object(help="All possible words from other students", scope=Scope.content)
|
all_words = Object(help="All possible words from other students", scope=Scope.content)
|
||||||
top_words = Object(help="Top N words for word cloud", scope=Scope.content)
|
top_words = Object(help="Top N words for word cloud", scope=Scope.content)
|
||||||
|
|
||||||
|
|
||||||
class WordCloudModule(WordCloudFields, XModule):
|
class WordCloudModule(WordCloudFields, XModule):
|
||||||
"""WordCloud Module"""
|
"""WordCloud Module"""
|
||||||
js = {
|
js = {
|
||||||
'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee')],
|
'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee')],
|
||||||
'js': [resource_string(__name__, 'js/src/word_cloud/logme.js'),
|
'js': [resource_string(__name__, 'js/src/word_cloud/logme.js'),
|
||||||
resource_string(__name__, 'js/src/word_cloud/d3.min.js'),
|
resource_string(__name__, 'js/src/word_cloud/d3.min.js'),
|
||||||
resource_string(__name__, 'js/src/word_cloud/d3.layout.cloud.js'),
|
resource_string(__name__, 'js/src/word_cloud/d3.layout.cloud.js'),
|
||||||
resource_string(__name__, 'js/src/word_cloud/word_cloud.js'),
|
resource_string(__name__, 'js/src/word_cloud/word_cloud.js'),
|
||||||
resource_string(__name__, 'js/src/word_cloud/word_cloud_main.js')]
|
resource_string(__name__, 'js/src/word_cloud/word_cloud_main.js')]
|
||||||
}
|
}
|
||||||
css = {'scss': [resource_string(__name__, 'css/word_cloud/display.scss')]}
|
css = {'scss': [resource_string(__name__, 'css/word_cloud/display.scss')]}
|
||||||
js_module_name = "WordCloud"
|
js_module_name = "WordCloud"
|
||||||
|
|
||||||
@@ -55,9 +55,8 @@ class WordCloudModule(WordCloudFields, XModule):
|
|||||||
'status': 'success',
|
'status': 'success',
|
||||||
'submitted': True,
|
'submitted': True,
|
||||||
'student_words': {
|
'student_words': {
|
||||||
word:self.all_words[word] for
|
word: self.all_words[word] for word in self.student_words
|
||||||
word in self.student_words
|
},
|
||||||
},
|
|
||||||
'total_count': sum(self.all_words.itervalues()),
|
'total_count': sum(self.all_words.itervalues()),
|
||||||
'top_words': self.prepare_words(self.top_words)
|
'top_words': self.prepare_words(self.top_words)
|
||||||
})
|
})
|
||||||
@@ -76,8 +75,10 @@ class WordCloudModule(WordCloudFields, XModule):
|
|||||||
|
|
||||||
def prepare_words(self, words):
|
def prepare_words(self, words):
|
||||||
"""Convert words dictionary for client API."""
|
"""Convert words dictionary for client API."""
|
||||||
return [{'text': word, 'size': count} for
|
return [
|
||||||
word, count in words.iteritems()]
|
{'text': word, 'size': count} for
|
||||||
|
word, count in words.iteritems()
|
||||||
|
]
|
||||||
|
|
||||||
def top_dict(self, dict_obj, amount):
|
def top_dict(self, dict_obj, amount):
|
||||||
"""Return new dict: top of dict using dict value."""
|
"""Return new dict: top of dict using dict value."""
|
||||||
@@ -124,8 +125,10 @@ class WordCloudModule(WordCloudFields, XModule):
|
|||||||
temp_all_words[word] = temp_all_words.get(word, 0) + 1
|
temp_all_words[word] = temp_all_words.get(word, 0) + 1
|
||||||
|
|
||||||
# Update top_words.
|
# Update top_words.
|
||||||
self.top_words = self.top_dict(temp_all_words,
|
self.top_words = self.top_dict(
|
||||||
int(self.num_top_words))
|
temp_all_words,
|
||||||
|
int(self.num_top_words)
|
||||||
|
)
|
||||||
|
|
||||||
# Save all_words in database.
|
# Save all_words in database.
|
||||||
self.all_words = temp_all_words
|
self.all_words = temp_all_words
|
||||||
@@ -142,13 +145,13 @@ class WordCloudModule(WordCloudFields, XModule):
|
|||||||
def get_html(self):
|
def get_html(self):
|
||||||
"""Renders parameters to template."""
|
"""Renders parameters to template."""
|
||||||
params = {
|
params = {
|
||||||
'element_id': self.location.html_id(),
|
'element_id': self.location.html_id(),
|
||||||
'element_class': self.location.category,
|
'element_class': self.location.category,
|
||||||
'ajax_url': self.system.ajax_url,
|
'ajax_url': self.system.ajax_url,
|
||||||
'configuration_json': self.get_state(),
|
'configuration_json': self.get_state(),
|
||||||
'num_inputs': int(self.num_inputs),
|
'num_inputs': int(self.num_inputs),
|
||||||
'submitted': self.submitted
|
'submitted': self.submitted
|
||||||
}
|
}
|
||||||
self.content = self.system.render_template('word_cloud.html', params)
|
self.content = self.system.render_template('word_cloud.html', params)
|
||||||
return self.content
|
return self.content
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user