GithubHelp home page GithubHelp logo

rusticisoftware / tincanpython Goto Github PK

View Code? Open in Web Editor NEW
47.0 22.0 37.0 667 KB

Python Library for xAPI (originally Tin Can API)

Home Page: http://rusticisoftware.github.io/TinCanPython/

License: Apache License 2.0

Python 100.00%
xapi tincan python python-library

tincanpython's People

Contributors

brianjmiller avatar bscscorm avatar fishhooks avatar redglow avatar stopic13 avatar usernolan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tincanpython's Issues

Got strange result from the example_script with ADL_LRS

I've just installed the reference implementation of the LRS at https://github.com/adlnet/ADL_LRS.
Then I've tried to access it from a Python shell using this TinCanPython library and the code of the example_script.
As I'm explaining below, I was puzzled by inconsistent results.

The script goes in error when trying to retrieve the statement:

Now, retrieving statement...
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "...\example_script.py", line 88, in <module>
    response = lrs.retrieve_statement(response.content.id)
AttributeError: 'NoneType' object has no attribute 'id'

If I inspect the response object just after save_statement, I get

>>> response
<tincan.lrs_response.LRSResponse object at 0x04AC95F0>
>>> response.success
False
>>> response.response.status
500
>>> response.data
u'[Errno 111] Connection refused'

However,

  1. By accessing the LRS from its web interface (Django application), I see that the statement has been correctly recorded.
  2. I am also able to retrieve the statement, by executing the subsequent code of the example_script and putting as argument the literal id taken from said interface in place of the expression response.content.id

iso8601 bug

Hi,

someone copied your conversion from datetime.timedelta to iso8601 to Stack Overflow, and I spotted a bug in it. If you add these two tests they will fail:

iso = jsonify_timedelta(timedelta(seconds=10))
self.assertEqual(iso, 'PT10S') #will return PT1S
iso = jsonify_timedelta(timedelta(seconds=60))
self.assertEqual(iso, 'PT01M') #will return PT1MS

Attachment properties names not match to xAPI specification

In tincan code for Attachment entity tincan/attachment.py names of properties are here:

class Attachment(SerializableBase):
    _props_req = [
        "usage_type",
        "display",
        "content_type",
        "length",
        "sha2"
    ]

    _props = [
        "description",
        "fileurl"
    ]

BUT in adlnet xAPI-Spec names of properties are different (usageType, contentType, fileUrl):
13

Q: Which version of xAPI does this library support?

I'm looking for a Python module to help emit xAPI event JSON. I see this module still goes by the old "Tin Can" name, so I was wondering whether it supports the most recent version (or a relatively recent one) of the xAPI specification.

StatementRef does not serialize 'objectType' when not passed in

StatementRef (and any others that have an 'objectType') should always serialize their 'objectType' even when not created with it. Need to unit test that case.

This fixes the issue with the Remote LRS unit test 'save_statement_ref'. I added a failing unit test to mark this.

Not able to save and retrive the statements

Hi,

I have changed the Following configuration params from the main.py and ran the script, Below is the exception I'm getting.

constructing the LRS...
...done
constructing the Actor...
...done
constructing the Verb...
...done
constructing the Object...
...done
constructing the Context...
...done
constructing the Statement...
...done
saving the Statement... Traceback (most recent call last):
File "C:\Python27\myscripts\SVNFOLDER\lRS_Scripiting\main.py", line 86, in
<tincan.lrs_response.LRSResponse object at 0x0000000002F76CF8>
...done
Now, retrieving statement...
response = lrs.retrieve_statement(response.content.id)
AttributeError: 'NoneType' object has no attribute 'id'

Could you please help me

Python 3 Support

๐Ÿ‘‹

Hi there! I noticed there's a PR open to support Python 3. Interested in using this library, but would prefer to use Python3.

Could you let me know if there are plans to merge this PR?

Many thanks! โœจ

Error running examples/example.py

I'm using the demo from learning locker as LRS http://demo.learninglocker.net/data/xAPI and the example throws this error in iptython

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/home/felipillo/dev/tincan/example_script.py in <module>()
     84 # retrieve our statement from the remote_lrs using the id returned in the response
     85 print "Now, retrieving statement..."
---> 86 response = lrs.retrieve_statement(response.content.id)
     87 
     88 if not response.success:

/home/felipillo/dev/tincan/lib/python2.7/site-packages/tincan/remote_lrs.pyc in retrieve_statement(self, statement_id)
    251 
    252         if lrs_response.success:
--> 253             lrs_response.content = Statement.from_json(lrs_response.data)
    254 
    255         return lrs_response

/home/felipillo/dev/tincan/lib/python2.7/site-packages/tincan/serializable_base.pyc in from_json(cls, json_data)
     83         """
     84         data = json.loads(json_data)
---> 85         result = cls(data)
     86         if hasattr(result, "_from_json"):
     87             result._from_json()

/home/felipillo/dev/tincan/lib/python2.7/site-packages/tincan/serializable_base.pyc in __init__(self, *args, **kwargs)
     64                 new_kwargs.pop(camel)
     65 
---> 66         super(SerializableBase, self).__init__(**new_kwargs)
     67 
     68     @classmethod

/home/felipillo/dev/tincan/lib/python2.7/site-packages/tincan/base.pyc in __init__(self, *args, **kwargs)
     43 
     44         for k, v in new_kwargs.iteritems():
---> 45             setattr(self, k, v)
     46 
     47     def __setattr__(self, attr, value):

/home/felipillo/dev/tincan/lib/python2.7/site-packages/tincan/base.pyc in __setattr__(self, attr, value)
     63                     attr,
     64                     self.__class__.__name__,
---> 65                     ', '.join(self._props)
     66                 ))
     67         else:

AttributeError: Property 'statements' cannot be set on a 'tincan.Statement' object. Allowed properties: result, context, version, attachments, id, actor, verb, object, timestamp, stored, authority

Add 'active' and 'voided' param_keys to RemoteLRS query_statements

I was trying out TinCanPython with the Learning Locker LRS backend. I wanted to search for non-voided statements prior to a date using 'until'. However, the query_statements function returns voided as well as un-voided statements. I'm not sure about ALL LRSes, but at least Learning Locker supports queries for 'voided' and 'active" statements.

There is a bug in Learning Locker's handling of multiple query parameters (but that's an issue for their project, not TinCanPython). I tested adding 'voided' to the allowed param_keys and then querying for 'voided': False, and it does the right thing.

Use python-dateutil instead of python-aniso8601

I see that python-aniso8601 is being used so its installation is required. I would ask, can dateutil.parser (python-dateutil) be used instead ?

I've run a quick test after this change to conversions/iso8601.py and it looks as though timestamps for statements are posted to the LRS in utc:

[root@localhost conversions]# diff iso8601-old.py iso8601-new.py 
24c24,25
< import aniso8601

---
> #import aniso8601
> import dateutil.parser
204c205,206
<             return aniso8601.parse_datetime(value)

---
>             #return aniso8601.parse_datetime(value)
>       return dateutil.parser.parse(value)

My selfish reason for wanting this is that dateutil is available with RHEL's python without adding in extra software via pip (beyond TinCanPython). I also see that there is some community input on this - http://stackoverflow.com/questions/127803/how-to-parse-an-iso-8601-formatted-date-in-python.

LRS returns "Request header field is missing ':' separator" when using long username/passwords

When using the main.py test in TinCanPython with LearningLocker's LRS (https://github.com/LearningLocker/learninglocker), the LRS returns:

<title>400 Bad Request</title>

Bad Request

Your browser sent a request that this server could not understand.
Request header field is missing ':' separator.

Looking at the remote_lrs.py I find:

        auth_string = "Basic " + base64.encodestring(unicode(kwargs["username"]) +
                                                     ":" +
                                                     unicode(kwargs["password"]))[:-1]

base64.encodestring resulted in newlines added at the end and every 76 characters, so the header was being malformed by having the tail portion of the base64 encoded authentication string on a newline.

My suggestion is to use this instead:

        auth_string = "Basic " + base64.b64encode(unicode(kwargs["username"]) +
                                                     ":" +
                                                      unicode(kwargs["password"]))

Note: changed to use b64encode and remove [:-1].

conversions and documents folders missing from PyPI

After easy_install -ing:

parallels@ubuntu:/usr/local/lib/python2.7/dist-packages/tincan-0.0.1-py2.7.egg/tincan$ ls | cat
about.py
about.pyc
activity_definition.py
activity_definition.pyc
activity_list.py
activity_list.pyc
activity.py
activity.pyc
agent_account.py
agent_account.pyc
agent_list.py
agent_list.pyc
agent.py
agent.pyc
attachment_list.py
attachment_list.pyc
attachment.py
attachment.pyc
base.py
base.pyc
context_activities.py
context_activities.pyc
context.py
context.pyc
extensions.py
extensions.pyc
group.py
group.pyc
http_request.py
http_request.pyc
__init__.py
__init__.pyc
interaction_component_list.py
interaction_component_list.pyc
interaction_component.py
interaction_component.pyc
language_map.py
language_map.pyc
lrs_response.py
lrs_response.pyc
remote_lrs.py
remote_lrs.pyc
result.py
result.pyc
score.py
score.pyc
serializable_base.py
serializable_base.pyc
statement_base.py
statement_base.pyc
statement_list.py
statement_list.pyc
statement.py
statement.pyc
statement_ref.py
statement_ref.pyc
statements_result.py
statements_result.pyc
statement_targetable.py
statement_targetable.pyc
substatement.py
substatement.pyc
typed_list.py
typed_list.pyc
verb.py
verb.pyc
version.py
version.pyc

Group from list

Shouldn't allow creation of a Group from a list. Should always be a dict, may or may not have a 'member' key.

Group with empty member list violates spec?

I've noticed LRS.io (Veracity LRS) does not accept statements from this library which has an "empty list" for the member field of a Group (as is the default in this implementation), it only allows member lists with one or more element, or with the member field missing.

I've patched my own version of group.py to accept None as the default for member rather than empty list (which ends up being omitted) to work around this, but perhaps this could be the default on this implementation too.

    def __init__(self, *args, **kwargs):
        self._object_type = None
        self._member = None

        super(Group, self).__init__(*args, **kwargs)

    def addmember(self, value):
        if self._member is None:
            self._member = AgentList()
        # ... etc.

    @member.setter
    def member(self, value):
        if value is None:
            self._member = None
        else:
           # ... etc.

query by agent

I would like to get all statements of a certain actor of an lrs. I am using a query with an agent where I specified a name. I am getting back the latest 100 statements but they are not filtered by the queried actor.

Truncated passwords?

Hopefully I'm just missing something obvious here, but I'm seeing some weird behavior when I try to use this library to submit a test record to my instance of learning locker. Other xAPI clients can submit, so I don't think it's a problem with the LRS.

Here's a pretty-printed excerpt from the reult.data JSON blob I get back after attempting to submit a score (with auth credentials obfuscated, of course):

{u'code': 401,
 u'error': True,
 u'message': u'Unauthorized request.',
 u'success': False,
 u'trace': [{u'args': [u'6e5exxxxxxxxxxxxxxxxxxxxxxxxxx54bf',
                       u'74337d9e58xxxxxx'],

Notice that the password appears to be truncated. Is this just a side-effect of how the data is being displayed, or could tincan.py be munging the password badly for some reason?

If anyone has tips on how to troubleshoot this and get it working, I would greatly appreciate it!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.