numbas / blackboard-scorm-analysis

A tool to analyse data about SCORM attempts from a Blackboard course archive
3 stars 1 forks source link

Reappearance of AttributeError: 'SpooledTemporaryFile' object has no attribute 'seekable' #5

Open zaript opened 4 years ago

zaript commented 4 years ago

There is a closed issue with this error (https://github.com/numbas/blackboard-scorm-analysis/issues/3), unfortunately, I have problem showing on two different systems.

Error message:

Traceback (most recent call last):
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 2309, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 2295, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1741, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/zaript/src/blackboard-scorm-analysis/server.py", line 83, in upload_zip
    zip.extractall(extract_path)
  File "/Users/zaript/miniconda3/lib/python3.7/zipfile.py", line 1636, in extractall
    self._extract_member(zipinfo, path, pwd)
  File "/Users/zaript/miniconda3/lib/python3.7/zipfile.py", line 1689, in _extract_member
    with self.open(member, pwd=pwd) as source, \
  File "/Users/zaript/miniconda3/lib/python3.7/zipfile.py", line 1516, in open
    self._fpclose, self._lock, lambda: self._writing)
  File "/Users/zaript/miniconda3/lib/python3.7/zipfile.py", line 734, in __init__
    self.seekable = file.seekable
AttributeError: 'SpooledTemporaryFile' object has no attribute 'seekable'

Installed packages:

(_pyvenv) > ~/s/blackboard-scorm-analysis git:(master)
> pip list
Package      Version
------------ -------
Click        7.0
Flask        1.0.2
itsdangerous 1.1.0
Jinja2       2.10.3
lxml         4.3.0
MarkupSafe   1.1.1
pip          19.3.1
pygal        2.4.0
setuptools   44.0.0
Werkzeug     0.16.0
wheel        0.33.6

Python version:

(_pyvenv) > ~/s/blackboard-scorm-analysis git:(master)
> python --version
Python 3.7.6
zaript commented 4 years ago

The fix seems to be to change line 77 in server.py:

            # zip = zipfile.ZipFile(file.stream)
            zip = zipfile.ZipFile(file)

The upload works normally with this fix, but then there is an issue with interpreting module archive:

Traceback (most recent call last):
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 2309, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 2295, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1741, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/zaript/src/blackboard-scorm-analysis/_pyvenv/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/zaript/src/blackboard-scorm-analysis/server.py", line 85, in upload_zip
    course = BlackboardCourse(extract_path)
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 228, in __init__
    self.load_hierarchy()
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 244, in load_hierarchy
    self.items = [self.load_item(item) for item in organization.xpath('item')]
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 244, in <listcomp>
    self.items = [self.load_item(item) for item in organization.xpath('item')]
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 260, in load_item
    item.subitems = [self.load_item(subelement) for subelement in element.xpath('item/item')]
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 260, in <listcomp>
    item.subitems = [self.load_item(subelement) for subelement in element.xpath('item/item')]
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 274, in load_item
    item.scorm = self.load_scorm(content_id)
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 285, in load_scorm
    scorm = SCORM(self,scorm_doc)
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 64, in __init__
    self.attempts = sorted([Attempt(self,registration) for registration in registrations],key=lambda a:a.userid)
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 64, in <listcomp>
    self.attempts = sorted([Attempt(self,registration) for registration in registrations],key=lambda a:a.userid)
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 105, in __init__
    self.objectives = sorted([Objective(self,objective) for objective in activity_run_time.xpath('ActivityRunTimeObjective')],key=lambda o: o.question)
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 105, in <listcomp>
    self.objectives = sorted([Objective(self,objective) for objective in activity_run_time.xpath('ActivityRunTimeObjective')],key=lambda o: o.question)
  File "/Users/zaript/src/blackboard-scorm-analysis/blackboardscorm.py", line 193, in __init__
    self.suspend_data = self.attempt.suspend_data['questions'][self.question-1]
TypeError: 'NoneType' object is not subscriptable
zaript commented 4 years ago

This is not an original issue anymore, but I will update the thread just in case someone needs it. Our BlackBoard archived course with an error, that seems to prevent this Analysis tool from opening a particular SCORM package in the archive. The workaround I have used is to skip the package with an error from loading.

Changes to line 260:

# item.subitems = [self.load_item(subelement) for subelement in element.xpath('item/item')]
item.subitems = []
for subelement in element.xpath('item/item'):
    try:
        item.subitems.append(self.load_item(subelement))
    except:
        print("***** failed to load subelement ", subelement)

This way I can still load and analyse the remaining part of the course.

davidhodge180 commented 2 years ago

I ran into these same issues in August 2022. I tried the bottom fix first (line 260) but it didn't work. Then I included the zip fix too (line 77) and it worked! Thanks