Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion learntools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
machine_learning, ml_explainability, ml_insights, ml_intermediate, python, \
sql

__version__ = '0.3.4'
__version__ = '0.3.5'
76 changes: 74 additions & 2 deletions learntools/core/tracking.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import enum
from IPython.display import display, Javascript
import json

import learntools
import os

# If set to True, then echo logged events as output.
DEBUG = False

USE_KAGGLESDK = os.environ.get('LEARN_USE_KAGGLE_SDK') == 'True'
if USE_KAGGLESDK:
from kagglesdk import KaggleClient
from kagglesdk.education.types.education_api_service import ApiTrackExerciseInteractionRequest
from kagglesdk.education.types.education_service import LearnExerciseInteractionType, LearnExerciseOutcomeType, LearnExerciseQuestionType

class InteractionType(enum.Enum):
CHECK = 1
HINT = 2
Expand All @@ -32,7 +38,67 @@ class QuestionType(enum.Enum):
trace = '',
)

def track(event):
def interaction_type_to_kagglesdk(event):
switch = {
InteractionType.CHECK: LearnExerciseInteractionType.CHECK,
InteractionType.HINT: LearnExerciseInteractionType.HINT,
InteractionType.SOLUTION: LearnExerciseInteractionType.SOLUTION,
}
value = event['interactionType']
assert value in switch
return switch.get(value)

def outcome_type_to_kagglesdk(interaction_type, event):
switch = {
OutcomeType.PASS: LearnExerciseOutcomeType.PASS,
OutcomeType.FAIL: LearnExerciseOutcomeType.FAIL,
OutcomeType.EXCEPTION: LearnExerciseOutcomeType.EXCEPTION,
OutcomeType.UNATTEMPTED: LearnExerciseOutcomeType.UNATTEMPTED,
}

value = event.get('outcomeType', None)
if value:
assert value in switch
return switch.get(value)
else:
assert interaction_type != LearnExerciseInteractionType.CHECK, "Check events must have an OutcomeType set: {!r}".format(event)
return LearnExerciseOutcomeType.LEARN_EXERCISE_OUTCOME_TYPE_UNSPECIFIED

def question_type_to_kagglesdk(event):
switch = {
QuestionType.EQUALITYCHECKPROBLEM: LearnExerciseQuestionType.EQUALITY_CHECK_PROBLEM,
QuestionType.CODINGPROBLEM: LearnExerciseQuestionType.CODING_PROBLEM,
QuestionType.FUNCTIONPROBLEM: LearnExerciseQuestionType.FUNCTION_PROBLEM,
QuestionType.THOUGHTEXPERIMENT: LearnExerciseQuestionType.THOUGHT_EXPERIMENT,
}

question_type = event.get('questionType', None)
if question_type:
assert question_type in switch
return switch.get(question_type)
return None

def track_using_kagglesdk(event):
request = ApiTrackExerciseInteractionRequest()
request.learn_tools_version = str(learntools.__version__)
request.value_towards_completion = event.get('valueTowardsCompletion', 0.0)
request.interaction_type = interaction_type_to_kagglesdk(event)
request.outcome_type = outcome_type_to_kagglesdk(request.interaction_type, event)

question_type = question_type_to_kagglesdk(event)
if question_type:
request.question_type = question_type

# TODO(b/379083750): the following items are still TBD
# - set request.fork_parent_kernel_session_id
# - automatically handle authorization in KaggleClient
# - post the nudge information back to the client

client = KaggleClient()
result = client.education.education_api_client.track_exercise_interaction(request)


def track_using_iframe(event):
# TODO: could be nice to put some validation logic here.
for k, v in _EVENT_DEFAULTS.items():
event.setdefault(k, v)
Expand Down Expand Up @@ -65,3 +131,9 @@ def track(event):
display(Javascript(debug_js))
display(message)

def track(event):
if USE_KAGGLESDK:
track_using_kagglesdk(event)
else:
track_using_iframe(event)