diff --git a/CanvasGroupy/_modidx.py b/CanvasGroupy/_modidx.py index e5c8aab..ac70c36 100644 --- a/CanvasGroupy/_modidx.py +++ b/CanvasGroupy/_modidx.py @@ -6,9 +6,34 @@ 'git_url': 'https://github.com/FleischerResearchLab/CanvasGroupy', 'lib_path': 'CanvasGroupy'}, 'syms': { 'CanvasGroupy.assign': {'CanvasGroupy.assign.assign_groups': ('groupeng_assign.html#assign_groups', 'CanvasGroupy/assign.py')}, - 'CanvasGroupy.canvas_group': {}, + 'CanvasGroupy.canvas_group': { 'CanvasGroupy.canvas_group.CanvasGroup': ( 'canvas_group_creation.html#canvasgroup', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.__init__': ( 'canvas_group_creation.html#canvasgroup.__init__', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.assign_canvas_group': ( 'canvas_group_creation.html#canvasgroup.assign_canvas_group', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.auth_canvas': ( 'canvas_group_creation.html#canvasgroup.auth_canvas', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.create_group': ( 'canvas_group_creation.html#canvasgroup.create_group', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.create_group_category': ( 'canvas_group_creation.html#canvasgroup.create_group_category', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.get_course': ( 'canvas_group_creation.html#canvasgroup.get_course', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.get_group_categories': ( 'canvas_group_creation.html#canvasgroup.get_group_categories', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.join_canvas_group': ( 'canvas_group_creation.html#canvasgroup.join_canvas_group', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.set_course': ( 'canvas_group_creation.html#canvasgroup.set_course', + 'CanvasGroupy/canvas_group.py'), + 'CanvasGroupy.canvas_group.CanvasGroup.set_group_category': ( 'canvas_group_creation.html#canvasgroup.set_group_category', + 'CanvasGroupy/canvas_group.py')}, 'CanvasGroupy.core': {}, - 'CanvasGroupy.gh_group': { 'CanvasGroupy.gh_group.cd_cmd': ('gh_group_creation.html#cd_cmd', 'CanvasGroupy/gh_group.py'), + 'CanvasGroupy.gh_group': { 'CanvasGroupy.gh_group.GitHubGroup': ( 'gh_group_creation.html#githubgroup', + 'CanvasGroupy/gh_group.py'), + 'CanvasGroupy.gh_group.GitHubGroup.__init__': ( 'gh_group_creation.html#githubgroup.__init__', + 'CanvasGroupy/gh_group.py'), + 'CanvasGroupy.gh_group.cd_cmd': ('gh_group_creation.html#cd_cmd', 'CanvasGroupy/gh_group.py'), 'CanvasGroupy.gh_group.check_gh_auth': ( 'gh_group_creation.html#check_gh_auth', 'CanvasGroupy/gh_group.py'), 'CanvasGroupy.gh_group.command': ('gh_group_creation.html#command', 'CanvasGroupy/gh_group.py'), diff --git a/CanvasGroupy/canvas_group.py b/CanvasGroupy/canvas_group.py index 267d8a7..fee2315 100644 --- a/CanvasGroupy/canvas_group.py +++ b/CanvasGroupy/canvas_group.py @@ -1,12 +1,107 @@ # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_canvas_group_creation.ipynb. # %% auto 0 -__all__ = [] +__all__ = ['CanvasGroup'] # %% ../nbs/03_canvas_group_creation.ipynb 3 -from .assign import * -from .gh_group import * +from canvasapi import Canvas +import canvasapi -# %% ../nbs/03_canvas_group_creation.ipynb 4 -#| export +# %% ../nbs/03_canvas_group_creation.ipynb 5 +class CanvasGroup(): + def __init__(self, + API_URL="https://canvas.ucsd.edu", # the domain name of canvas + API_KEY="", # Integrations' API generated by canvas + course_id="" # Course ID, can be found in the course url + ): + "Initialize Canvas Group within a Group Set and its appropriate memberships" + self.API_URL = API_URL + self.canvas = None + self.course = None + self.group_category = None + self.group_categories = None + self.groups = None + self.users = None + self.email_to_canvas_id = None + + # initialize by the input parameter + if API_KEY != "": + self.auth_canvas(API_KEY) + if course_id != "": + self.set_course(course_id) + self.get_group_categories() + + def auth_canvas(self, + API_key: str # the Authenticator key generated from canvas + ): + "Authorize the canvas module with API_KEY" + self.canvas = Canvas(self.API_URL, API_KEY) + + def set_course(self, + course_id: int # the course id of the target course + ): + "Set the target course by the course ID" + self.course = self.canvas.get_course(course_id) + self.users = list(self.course.get_users()) + self.email_to_canvas_id = {u.email.split("@")[0]: u.id for u in self.users} + + def set_group_category(self, + category_name: str # the target group category + ) -> canvasapi.group.GroupCategory: # target group category object + try: + self.group_category = self.group_categories[category_name] + except KeyError: + raise KeyError(f"{category_name} did not found in the group categories." + f"\n Try to create one with CanvasGroup.create_group_category") + return self.group_category + + def get_course(self): + return self.course + + def get_group_categories(self) -> dict: # return a name / group category object + "Grab all existing group category (group set) in this course" + categories = list(self.course.get_group_categories()) + self.group_categories = {cat.name: cat for cat in categories} + return {cat.name: cat for cat in categories} + + def create_group_category(self, + params: dict # the parameter of canvas group category API @ [this link](https://canvas.instructure.com/doc/api/group_categories.html#method.group_categories.create) + ) -> canvasapi.group.GroupCategory: # the generated group category object + "Create group category (group set) in this course" + self.group_category = self.course.create_group_category(**params) + return self.group_category + + def create_group(self, + params: dict, #the parameter of canvas group create API at [this link](https://canvas.instructure.com/doc/api/groups.html#method.groups.create) + ) -> canvasapi.group.Group: # the generated target group object + "Create canvas group under the target group category" + if self.group_category is None: + raise ValueError("Have you specified or create a group category (group set)?") + return self.group_category.create_group(**params) + + def join_canvas_group(self, + group: canvasapi.group.Group, # the group that students will join + group_members:[str], # list of group member's SIS Login (email prefix, before the @.) + ) -> [str]: # list of unsuccessful join + "Add membership access of each group member into the group" + unsuccessful_join = [] + for group_member in group_members: + try: + canvas_id = self.email_to_canvas_id[group_member] + except KeyError: + unsuccessful_join.append(group_member) + print(f"Error adding student {group_member} \n into group {group.name}") + group.create_membership(canvas_id) + return unsuccessful_join + + def assign_canvas_group(self, + group_name: str, # group name, display on canvas + group_members:[str], # list of group member's SIS Login + in_group_category: str, # specify which group category the group belongs to + ) -> [str]: # list of unsuccessful join + "Create new groups and assign group member into the class in the `self.group_category`" + self.set_group_category(in_group_category) + group = self.create_group({"name": group_name}) + unsuccessful_join = self.join_canvas_group(group, group_members) + return unsuccessful_join diff --git a/CanvasGroupy/core.py b/CanvasGroupy/core.py index 9cd55a4..91308b9 100644 --- a/CanvasGroupy/core.py +++ b/CanvasGroupy/core.py @@ -6,7 +6,3 @@ # %% ../nbs/00_core.ipynb 3 from .assign import * from .gh_group import * - -# %% ../nbs/00_core.ipynb 4 -#| export - diff --git a/CanvasGroupy/gh_group.py b/CanvasGroupy/gh_group.py index 8f14efc..cb6e3b6 100644 --- a/CanvasGroupy/gh_group.py +++ b/CanvasGroupy/gh_group.py @@ -1,10 +1,21 @@ # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_gh_group_creation.ipynb. # %% auto 0 -__all__ = ['command', 'check_gh_auth', 'git_creat_repo_cmd', 'git_manage_access_cmd', 'cd_cmd', 'git_rename_cmd', 'git_commit', - 'git_add_all', 'delete_directory'] +__all__ = ['GitHubGroup', 'command', 'check_gh_auth', 'git_creat_repo_cmd', 'git_manage_access_cmd', 'cd_cmd', 'git_rename_cmd', + 'git_commit', 'git_add_all', 'delete_directory'] # %% ../nbs/02_gh_group_creation.ipynb 3 +from github import Github + +# %% ../nbs/02_gh_group_creation.ipynb 4 +class GitHubGroup(): + def __init__(self, + token="", + org="" + ): + return ... + +# %% ../nbs/02_gh_group_creation.ipynb 8 def command(cmd: str # command to call in bash ) -> (bool, str): # success, output "Execute the given command in shell" @@ -21,7 +32,7 @@ def command(cmd: str # command to call in bash print(output.decode()) return success, output -# %% ../nbs/02_gh_group_creation.ipynb 4 +# %% ../nbs/02_gh_group_creation.ipynb 9 def check_gh_auth() -> bool: # whether you have authenticate "Check whether you have gh auth configured" msg = command("gh auth status")[1] @@ -29,7 +40,7 @@ def check_gh_auth() -> bool: # whether you have authenticate return False return True -# %% ../nbs/02_gh_group_creation.ipynb 5 +# %% ../nbs/02_gh_group_creation.ipynb 10 def git_creat_repo_cmd(repo_name:str, # the name of the created repository repo_org: str, # the GitHub organization name template_repo:str, # the template repository that the new repo will use @@ -44,7 +55,7 @@ def git_creat_repo_cmd(repo_name:str, # the name of the created repository cmd = f"{cmd} --clone {repo_org}/{repo_name}" return cmd -# %% ../nbs/02_gh_group_creation.ipynb 7 +# %% ../nbs/02_gh_group_creation.ipynb 12 def git_manage_access_cmd(repo_name:str, # the name of the created repository repo_org: str, # the GitHub organization name that the repo belongs to collaorator_id: str, # the GitHub id of the collaborator, or team name if `add_team=True` @@ -59,30 +70,30 @@ def git_manage_access_cmd(repo_name:str, # the name of the created repository return cmd -# %% ../nbs/02_gh_group_creation.ipynb 10 +# %% ../nbs/02_gh_group_creation.ipynb 15 def cd_cmd(target_dir: str # the target directory we want to change to ) -> str: # the command of cd "Unix command for change directory" return f"cd {target_dir}" -# %% ../nbs/02_gh_group_creation.ipynb 11 +# %% ../nbs/02_gh_group_creation.ipynb 16 def git_rename_cmd(source: str, # the original name of the file target: str # the target name of the file ) -> str: # the command of git rename file "GitHub mv command to rename file in the directory" return f"git mv {source} {target}" -# %% ../nbs/02_gh_group_creation.ipynb 12 +# %% ../nbs/02_gh_group_creation.ipynb 17 def git_commit(commit_msg: str, # Commit Message ) -> str: # the command for git commit "GitHub commit command" return f'git commit -m "{commit_msg}"' -# %% ../nbs/02_gh_group_creation.ipynb 13 +# %% ../nbs/02_gh_group_creation.ipynb 18 def git_add_all(): return "git add -A" -# %% ../nbs/02_gh_group_creation.ipynb 14 +# %% ../nbs/02_gh_group_creation.ipynb 19 def delete_directory(dir_name: str # the directory that we want to delete ) -> str: # the command for delete dir return f"rm -rf {dir_name}" diff --git a/README.md b/README.md index f423def..faa5200 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -CanvasGroupy -================ +# CanvasGroupy diff --git a/_proc/00_core.ipynb b/_proc/00_core.ipynb index 2fac9b6..dc82abc 100644 --- a/_proc/00_core.ipynb +++ b/_proc/00_core.ipynb @@ -19,6 +19,38 @@ "source": [ "" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> gh auth status\n", + "usage: gh [-h] [--home] [-p] [-b] [-s] [-r] [-t] [-c] [-w] [-i] [-d] [-v]\n", + "gh: error: unrecognized arguments: auth status\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "check_gh_auth()" + ] } ], "metadata": { diff --git a/_proc/01_GroupEngAssign.ipynb b/_proc/01_GroupEngAssign.ipynb deleted file mode 100644 index 8fa4936..0000000 --- a/_proc/01_GroupEngAssign.ipynb +++ /dev/null @@ -1,301 +0,0 @@ -{ - "cells": [ - { - "cell_type": "raw", - "metadata": {}, - "source": [ - "---\n", - "description: Invoke Package Group Eng to Assign Student in Groups\n", - "output-file: groupengassign.html\n", - "title: GroupEngAssign\n", - "\n", - "---\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/assign.py#L9){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### assign_groups\n", - "\n", - "> assign_groups (groupeng_config:str)\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| groupeng_config | str | Directory for the GroupEng config yml file |\n", - "| **Returns** | **(, )** | **Status and output directory of the compile file.** |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/assign.py#L9){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### assign_groups\n", - "\n", - "> assign_groups (groupeng_config:str)\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| groupeng_config | str | Directory for the GroupEng config yml file |\n", - "| **Returns** | **(, )** | **Status and output directory of the compile file.** |" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#| echo: false\n", - "#| output: asis\n", - "show_doc(assign_groups)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "language": "python" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['sample_group_specification.groupeng', '.DS_Store', 'sample_group_specification_annotated.groupeng', 'sample_class_1.csv', '.ipynb_checkpoints']\n" - ] - } - ], - "source": [ - "print(os.listdir(\"example\")) # take a look at the example files name" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "language": "python" - }, - "outputs": [], - "source": [ - "status, outdir = assign_groups(\"example/sample_group_specification.groupeng\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "language": "python" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(False, 'groups_example_2023-04-14_17-36-01')" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# take a look at the output\n", - "status, outdir" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The false means that at least one requirment is not satisfied. We can take a look at the file that was generated." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "language": "python" - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
IDGPAGenderEthnicityMajorSkill1Skill2Skill3Project choiceGroup NumberUnnamed: 10group GPA meanRules Broken
0372.636350M-Civ Eyy-nanotech1.0NaNNaNNaN
1412.225582F-Civ Eyyyrobotics1.0NaNNaNNaN
2614.220161M-Mech E--ystatistics1.0NaNNaNNaN
3632.976609F-EEy-yautomotive1.0NaNNaNNaN
4753.775685F-CSyyystatistics1.0NaNNaNNaN
\n", - "
" - ], - "text/plain": [ - " ID GPA Gender Ethnicity Major Skill1 Skill2 Skill3 Project choice \\\n", - "0 37 2.636350 M - Civ E y y - nanotech \n", - "1 41 2.225582 F - Civ E y y y robotics \n", - "2 61 4.220161 M - Mech E - - y statistics \n", - "3 63 2.976609 F - EE y - y automotive \n", - "4 75 3.775685 F - CS y y y statistics \n", - "\n", - " Group Number Unnamed: 10 group GPA mean Rules Broken \n", - "0 1.0 NaN NaN NaN \n", - "1 1.0 NaN NaN NaN \n", - "2 1.0 NaN NaN NaN \n", - "3 1.0 NaN NaN NaN \n", - "4 1.0 NaN NaN NaN " - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "details = pd.read_csv(os.path.join(outdir, \"example_details.csv\"), on_bad_lines='skip')\n", - "details.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following package will generate Canvas and GitHub groups based on this generated csv files." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "python3", - "language": "python", - "name": "python3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/_proc/02_gh_group_creation.ipynb b/_proc/02_gh_group_creation.ipynb index f7f9b7d..39410ee 100644 --- a/_proc/02_gh_group_creation.ipynb +++ b/_proc/02_gh_group_creation.ipynb @@ -30,7 +30,73 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L8){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L11){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### GitHubGroup\n", + "\n", + "> GitHubGroup (token='', org='')\n", + "\n", + "Initialize self. See help(type(self)) for accurate signature." + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L11){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### GitHubGroup\n", + "\n", + "> GitHubGroup (token='', org='')\n", + "\n", + "Initialize self. See help(type(self)) for accurate signature." + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(GitHubGroup)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# If you wish to use `gh`" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L19){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### command\n", "\n", @@ -46,7 +112,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L8){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L19){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### command\n", "\n", @@ -60,7 +126,7 @@ "| **Returns** | **(, )** | **success, output** |" ] }, - "execution_count": 1, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -73,7 +139,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -81,7 +147,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L25){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L36){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### check_gh_auth\n", "\n", @@ -92,7 +158,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L25){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L36){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### check_gh_auth\n", "\n", @@ -101,7 +167,7 @@ "Check whether you have gh auth configured" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -114,7 +180,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -122,7 +188,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L33){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L44){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_creat_repo_cmd\n", "\n", @@ -142,7 +208,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L33){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L44){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_creat_repo_cmd\n", "\n", @@ -160,7 +226,7 @@ "| **Returns** | **str** | | **the command of repo creation** |" ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -196,7 +262,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -204,7 +270,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L48){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L59){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_manage_access_cmd\n", "\n", @@ -225,7 +291,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L48){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L59){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_manage_access_cmd\n", "\n", @@ -244,7 +310,7 @@ "| **Returns** | **str** | | **the command of repo creation** |" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -264,7 +330,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -272,7 +338,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L63){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L74){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### cd_cmd\n", "\n", @@ -288,7 +354,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L63){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L74){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### cd_cmd\n", "\n", @@ -302,7 +368,7 @@ "| **Returns** | **str** | **the command of cd** |" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -315,7 +381,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -323,7 +389,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L69){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L80){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_rename_cmd\n", "\n", @@ -340,7 +406,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L69){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L80){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_rename_cmd\n", "\n", @@ -355,7 +421,7 @@ "| **Returns** | **str** | **the command of git rename file** |" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -368,7 +434,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -376,7 +442,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L76){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L87){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_commit\n", "\n", @@ -392,7 +458,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L76){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L87){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_commit\n", "\n", @@ -406,7 +472,7 @@ "| **Returns** | **str** | **the command for git commit** |" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -419,7 +485,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -427,7 +493,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L82){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L93){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_add_all\n", "\n", @@ -436,14 +502,14 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L82){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L93){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### git_add_all\n", "\n", "> git_add_all ()" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -456,7 +522,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -464,7 +530,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L86){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L97){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### delete_directory\n", "\n", @@ -478,7 +544,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L86){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/gh_group.py#L97){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### delete_directory\n", "\n", @@ -490,7 +556,7 @@ "| **Returns** | **str** | **the command for delete dir** |" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } diff --git a/_proc/03_canvas_group_creation.ipynb b/_proc/03_canvas_group_creation.ipynb index c1fded6..12238c6 100644 --- a/_proc/03_canvas_group_creation.ipynb +++ b/_proc/03_canvas_group_creation.ipynb @@ -19,6 +19,774 @@ "source": [ "" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Canvas Group Modules" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L11){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup\n", + "\n", + "> CanvasGroup (API_URL='https://canvas.ucsd.edu', API_KEY='', course_id='')\n", + "\n", + "Initialize Canvas Group within a Group Set and its appropriate memberships\n", + "\n", + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| API_URL | str | https://canvas.ucsd.edu | the domain name of canvas |\n", + "| API_KEY | str | | Integrations' API generated by canvas |\n", + "| course_id | str | | Course ID, can be found in the course url |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L11){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup\n", + "\n", + "> CanvasGroup (API_URL='https://canvas.ucsd.edu', API_KEY='', course_id='')\n", + "\n", + "Initialize Canvas Group within a Group Set and its appropriate memberships\n", + "\n", + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| API_URL | str | https://canvas.ucsd.edu | the domain name of canvas |\n", + "| API_KEY | str | | Integrations' API generated by canvas |\n", + "| course_id | str | | Course ID, can be found in the course url |" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(CanvasGroup)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Canvas Authentication" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If `API_KEY` and/or `course_id` was passed into the initializer, it will call the following methods to load the relevant information about your canvas and your canvas course.\n", + "\n", + "Alternatively, you can manually set them after you created the [`CanvasGroup`](https://FleischerResearchLab.github.io/CanvasGroupy/canvas_group_creation.html#canvasgroup) object" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L34){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.auth_canvas\n", + "\n", + "> CanvasGroup.auth_canvas (API_key:str)\n", + "\n", + "Authorize the canvas module with API_KEY\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| API_key | str | the Authenticator key generated from canvas |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L34){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.auth_canvas\n", + "\n", + "> CanvasGroup.auth_canvas (API_key:str)\n", + "\n", + "Authorize the canvas module with API_KEY\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| API_key | str | the Authenticator key generated from canvas |" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(CanvasGroup.auth_canvas)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L40){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.set_course\n", + "\n", + "> CanvasGroup.set_course (course_id:int)\n", + "\n", + "Set the target course by the course ID\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| course_id | int | the course id of the target course |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L40){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.set_course\n", + "\n", + "> CanvasGroup.set_course (course_id:int)\n", + "\n", + "Set the target course by the course ID\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| course_id | int | the course id of the target course |" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(CanvasGroup.set_course)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [], + "source": [ + "# instansiate a new Canvas Group Object \n", + "# if your class size is large, it will take around 2 minutes to grab all student info.\n", + "cg = CanvasGroup(API_URL, API_KEY, course_id=course_id)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create / Assign Group in One Call" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L97){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.assign_canvas_group\n", + "\n", + "> CanvasGroup.assign_canvas_group (group_name:str,\n", + "> group_members:[],\n", + "> in_group_category:str)\n", + "\n", + "Create new groups and assign group member into the class in the `self.group_category`\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| group_name | str | group name, display on canvas |\n", + "| group_members | [] | list of group member's SIS Login |\n", + "| in_group_category | str | specify which group category the group belongs to |\n", + "| **Returns** | **[]** | **list of unsuccessful join** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L97){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.assign_canvas_group\n", + "\n", + "> CanvasGroup.assign_canvas_group (group_name:str,\n", + "> group_members:[],\n", + "> in_group_category:str)\n", + "\n", + "Create new groups and assign group member into the class in the `self.group_category`\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| group_name | str | group name, display on canvas |\n", + "| group_members | [] | list of group member's SIS Login |\n", + "| in_group_category | str | specify which group category the group belongs to |\n", + "| **Returns** | **[]** | **list of unsuccessful join** |" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(CanvasGroup.assign_canvas_group)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this way, we could directly create canvas group by specifying the group name, members info, and the group category directly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "member2 = \"email2\"\n", + "unsuccessful = cg.assign_canvas_group(\n", + " group_name=\"Group02-SP23\", \n", + " group_members=[member2], \n", + " in_group_category=\"Group Project 1\"\n", + ")\n", + "unsuccessful" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that it will throw a Value Error if the target `in_group_category` did not exist in the course." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'Group Project 2 did not found in the group categories.\\n Try to create one with CanvasGroup.create_group_category'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[99], line 44\u001b[0m, in \u001b[0;36mCanvasGroup.set_group_category\u001b[0;34m(self, category_name)\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 44\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgroup_category \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mgroup_categories\u001b[49m\u001b[43m[\u001b[49m\u001b[43mcategory_name\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 45\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n", + "\u001b[0;31mKeyError\u001b[0m: 'Group Project 2'", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[101], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mcg\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43massign_canvas_group\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2\u001b[0m \u001b[43m \u001b[49m\u001b[43mgroup_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mFailed\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3\u001b[0m \u001b[43m \u001b[49m\u001b[43mgroup_members\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43mmember2\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4\u001b[0m \u001b[43m \u001b[49m\u001b[43min_group_category\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mGroup Project 2\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[1;32m 5\u001b[0m \u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[99], line 95\u001b[0m, in \u001b[0;36mCanvasGroup.assign_canvas_group\u001b[0;34m(self, group_name, group_members, in_group_category)\u001b[0m\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21massign_canvas_group\u001b[39m(\u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 90\u001b[0m group_name: \u001b[38;5;28mstr\u001b[39m, \u001b[38;5;66;03m# group name, display on canvas\u001b[39;00m\n\u001b[1;32m 91\u001b[0m group_members:[\u001b[38;5;28mstr\u001b[39m], \u001b[38;5;66;03m# list of group member's SIS Login\u001b[39;00m\n\u001b[1;32m 92\u001b[0m in_group_category: \u001b[38;5;28mstr\u001b[39m, \u001b[38;5;66;03m# specify which group category the group belongs to\u001b[39;00m\n\u001b[1;32m 93\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m [\u001b[38;5;28mstr\u001b[39m]: \u001b[38;5;66;03m# list of unsuccessful join\u001b[39;00m\n\u001b[1;32m 94\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCreate new groups and assign group member into the class in the `self.group_category`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 95\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_group_category\u001b[49m\u001b[43m(\u001b[49m\u001b[43min_group_category\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 96\u001b[0m group \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcreate_group({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m: group_name})\n\u001b[1;32m 97\u001b[0m unsuccessful_join \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mjoin_canvas_group(group, group_members)\n", + "Cell \u001b[0;32mIn[99], line 46\u001b[0m, in \u001b[0;36mCanvasGroup.set_group_category\u001b[0;34m(self, category_name)\u001b[0m\n\u001b[1;32m 44\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgroup_category \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgroup_categories[category_name]\n\u001b[1;32m 45\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n\u001b[0;32m---> 46\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcategory_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m did not found in the group categories.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 47\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m Try to create one with CanvasGroup.create_group_category\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 48\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgroup_category\n", + "\u001b[0;31mKeyError\u001b[0m: 'Group Project 2 did not found in the group categories.\\n Try to create one with CanvasGroup.create_group_category'" + ] + } + ], + "source": [ + "cg.assign_canvas_group(\n", + " group_name=\"Failed\",\n", + " group_members=[member2],\n", + " in_group_category=\"Group Project 2\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create / Set Target Group Category (Set)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L61){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.get_group_categories\n", + "\n", + "> CanvasGroup.get_group_categories ()\n", + "\n", + "Grab all existing group category (group set) in this course" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L61){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.get_group_categories\n", + "\n", + "> CanvasGroup.get_group_categories ()\n", + "\n", + "Grab all existing group category (group set) in this course" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(CanvasGroup.get_group_categories)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Final-Project_testing', 'Group Project 1']" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# list all current group category\n", + "list(cg.get_group_categories().keys())" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L67){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.create_group_category\n", + "\n", + "> CanvasGroup.create_group_category (params:dict)\n", + "\n", + "Create group category (group set) in this course\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| params | dict | the parameter of canvas group category API @ [this link](https://canvas.instructure.com/doc/api/group_categories.html#method.group_categories.create) |\n", + "| **Returns** | **GroupCategory** | **the generated group category object** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L67){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.create_group_category\n", + "\n", + "> CanvasGroup.create_group_category (params:dict)\n", + "\n", + "Create group category (group set) in this course\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| params | dict | the parameter of canvas group category API @ [this link](https://canvas.instructure.com/doc/api/group_categories.html#method.group_categories.create) |\n", + "| **Returns** | **GroupCategory** | **the generated group category object** |" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(CanvasGroup.create_group_category)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [], + "source": [ + "params = {\n", + " \"name\": \"Group Project 1\",\n", + " \"group_limit\": 5\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Our new group category (set) is called: Group Project 1\n" + ] + } + ], + "source": [ + "# create a new category\n", + "group_category = cg.create_group_category(params)\n", + "print(f\"Our new group category (set) is called: {group_category.name}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Final-Project_testing', 'Group Project 1']" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Check whether we successfully create a new group\n", + "list(cg.get_group_categories().keys())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When a group category is already created, we cannot create another group with the same name. To switch the group category destination of group creation, use the `set_group_category` methods." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L48){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.set_group_category\n", + "\n", + "> CanvasGroup.set_group_category (category_name:str)\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| category_name | str | the target group category |\n", + "| **Returns** | **GroupCategory** | **target group category object** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L48){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.set_group_category\n", + "\n", + "> CanvasGroup.set_group_category (category_name:str)\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| category_name | str | the target group category |\n", + "| **Returns** | **GroupCategory** | **target group category object** |" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(CanvasGroup.set_group_category)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [], + "source": [ + "group_category = cg.set_group_category(\"Final-Project_testing\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create a Group Inside the Target Group Category" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L74){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.create_group\n", + "\n", + "> CanvasGroup.create_group (params:dict)\n", + "\n", + "Create canvas group under the target group category\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| params | dict | the parameter of canvas group create API at [this link](https://canvas.instructure.com/doc/api/groups.html#method.groups.create) |\n", + "| **Returns** | **Group** | **the generated target group object** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L74){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.create_group\n", + "\n", + "> CanvasGroup.create_group (params:dict)\n", + "\n", + "Create canvas group under the target group category\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| params | dict | the parameter of canvas group create API at [this link](https://canvas.instructure.com/doc/api/groups.html#method.groups.create) |\n", + "| **Returns** | **Group** | **the generated target group object** |" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(CanvasGroup.create_group)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Group(_requester=, id=121649, name=Group01_SP23, created_at=2023-04-19T08:14:04Z, created_at_date=2023-04-19 08:14:04+00:00, max_membership=5, is_public=False, join_level=invitation_only, group_category_id=16167, description=None, members_count=0, storage_quota_mb=1024, storage_quota_mb_date=1024-01-01 00:00:00+00:00, permissions={'create_discussion_topic': True, 'join': False, 'create_announcement': True}, context_type=Course, course_id=45059, avatar_url=None, role=None, leader=None, users=[], group_category={'id': 16167, 'name': 'Final-Project_testing', 'role': None, 'self_signup': None, 'group_limit': 5, 'auto_leader': None, 'created_at': '2023-04-19T03:27:12Z', 'context_type': 'Course', 'course_id': 45059, 'protected': False, 'allows_multiple_memberships': False, 'is_member': False}, has_submission=False, concluded=False)" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = {\n", + " \"name\": \"Group01_SP23\",\n", + " \"join_level\": \"invitation_only\"\n", + "}\n", + "group1 = cg.create_group(params)\n", + "group1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Assign Student to the Group" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L82){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.join_canvas_group\n", + "\n", + "> CanvasGroup.join_canvas_group (group:canvasapi.group.Group,\n", + "> group_members:[])\n", + "\n", + "Add membership access of each group member into the group\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| group | Group | the group that students will join |\n", + "| group_members | [] | list of group member's SIS Login (email prefix, before the @.) |\n", + "| **Returns** | **[]** | **list of unsuccessful join** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/FleischerResearchLab/CanvasGroupy/blob/main/CanvasGroupy/canvas_group.py#L82){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### CanvasGroup.join_canvas_group\n", + "\n", + "> CanvasGroup.join_canvas_group (group:canvasapi.group.Group,\n", + "> group_members:[])\n", + "\n", + "Add membership access of each group member into the group\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| group | Group | the group that students will join |\n", + "| group_members | [] | list of group member's SIS Login (email prefix, before the @.) |\n", + "| **Returns** | **[]** | **list of unsuccessful join** |" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| echo: false\n", + "#| output: asis\n", + "show_doc(CanvasGroup.join_canvas_group)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "member1 = \"email\"\n", + "cg.join_canvas_group(group1, [member1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language": "python" + }, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/_proc/04_clean_up.ipynb b/_proc/04_clean_up.ipynb new file mode 100644 index 0000000..72f4311 --- /dev/null +++ b/_proc/04_clean_up.ipynb @@ -0,0 +1,44 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "---\n", + "description: Keep your local computer fresh and clean, without 200+ students groups\n", + " files.\n", + "output-file: clean_up.html\n", + "title: Clean-up and Tear Down\n", + "\n", + "---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53bcf9fe", + "metadata": { + "language": "python" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "python3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_proc/_docs/canvas_group_creation.html b/_proc/_docs/canvas_group_creation.html new file mode 100644 index 0000000..e6508fd --- /dev/null +++ b/_proc/_docs/canvas_group_creation.html @@ -0,0 +1,851 @@ + + + + + + + + + + +CanvasGroupy - Canvas Group Creation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Canvas Group Creation

+
+ +
+
+ Create canvas group via Canvas API +
+
+ + +
+ + + + +
+ + +
+ + +
+

Canvas Group Modules

+
+

source

+
+

CanvasGroup

+
+
 CanvasGroup (API_URL='https://canvas.ucsd.edu', API_KEY='', course_id='')
+
+

Initialize Canvas Group within a Group Set and its appropriate memberships

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
API_URLstrhttps://canvas.ucsd.eduthe domain name of canvas
API_KEYstrIntegrations’ API generated by canvas
course_idstrCourse ID, can be found in the course url
+
+
+

Canvas Authentication

+

If API_KEY and/or course_id was passed into the initializer, it will call the following methods to load the relevant information about your canvas and your canvas course.

+

Alternatively, you can manually set them after you created the CanvasGroup object

+
+

source

+
+

CanvasGroup.auth_canvas

+
+
 CanvasGroup.auth_canvas (API_key:str)
+
+

Authorize the canvas module with API_KEY

+ + + + + + + + + + + + + + + +
TypeDetails
API_keystrthe Authenticator key generated from canvas
+
+

source

+
+
+

CanvasGroup.set_course

+
+
 CanvasGroup.set_course (course_id:int)
+
+

Set the target course by the course ID

+ + + + + + + + + + + + + + + +
TypeDetails
course_idintthe course id of the target course
+
+
# instansiate a new Canvas Group Object 
+# if your class size is large, it will take around 2 minutes to grab all student info.
+cg = CanvasGroup(API_URL, API_KEY, course_id=course_id)
+
+
+
+
+

Create / Assign Group in One Call

+
+

source

+
+

CanvasGroup.assign_canvas_group

+
+
 CanvasGroup.assign_canvas_group (group_name:str,
+                                  group_members:[<class'str'>],
+                                  in_group_category:str)
+
+

Create new groups and assign group member into the class in the self.group_category

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDetails
group_namestrgroup name, display on canvas
group_members[<class ‘str’>]list of group member’s SIS Login
in_group_categorystrspecify which group category the group belongs to
Returns[<class ‘str’>]list of unsuccessful join
+

In this way, we could directly create canvas group by specifying the group name, members info, and the group category directly.

+
+
member2 = "email2"
+unsuccessful = cg.assign_canvas_group(
+    group_name="Group02-SP23", 
+    group_members=[member2], 
+    in_group_category="Group Project 1"
+)
+unsuccessful
+
+
[]
+
+
+

Note that it will throw a Value Error if the target in_group_category did not exist in the course.

+
+
cg.assign_canvas_group(
+    group_name="Failed",
+    group_members=[member2],
+    in_group_category="Group Project 2"
+)
+
+
KeyError: 'Group Project 2 did not found in the group categories.\n Try to create one with CanvasGroup.create_group_category'
+
+
+
+
+
+

Create / Set Target Group Category (Set)

+
+

source

+
+

CanvasGroup.get_group_categories

+
+
 CanvasGroup.get_group_categories ()
+
+

Grab all existing group category (group set) in this course

+
+
# list all current group category
+list(cg.get_group_categories().keys())
+
+
['Final-Project_testing', 'Group Project 1']
+
+
+
+

source

+
+
+

CanvasGroup.create_group_category

+
+
 CanvasGroup.create_group_category (params:dict)
+
+

Create group category (group set) in this course

+ + + + + + + + + + + + + + + + + + + + +
TypeDetails
paramsdictthe parameter of canvas group category API @ this link
ReturnsGroupCategorythe generated group category object
+
+
params = {
+    "name": "Group Project 1",
+    "group_limit": 5
+}
+
+
+
# create a new category
+group_category = cg.create_group_category(params)
+print(f"Our new group category (set) is called: {group_category.name}")
+
+
Our new group category (set) is called: Group Project 1
+
+
+
+
# Check whether we successfully create a new group
+list(cg.get_group_categories().keys())
+
+
['Final-Project_testing', 'Group Project 1']
+
+
+

When a group category is already created, we cannot create another group with the same name. To switch the group category destination of group creation, use the set_group_category methods.

+
+

source

+
+
+

CanvasGroup.set_group_category

+
+
 CanvasGroup.set_group_category (category_name:str)
+
+ + + + + + + + + + + + + + + + + + + + +
TypeDetails
category_namestrthe target group category
ReturnsGroupCategorytarget group category object
+
+
group_category = cg.set_group_category("Final-Project_testing")
+
+
+
+
+

Create a Group Inside the Target Group Category

+
+

source

+
+

CanvasGroup.create_group

+
+
 CanvasGroup.create_group (params:dict)
+
+

Create canvas group under the target group category

+ + + + + + + + + + + + + + + + + + + + +
TypeDetails
paramsdictthe parameter of canvas group create API at this link
ReturnsGroupthe generated target group object
+
+
params = {
+    "name": "Group01_SP23",
+    "join_level": "invitation_only"
+}
+group1 = cg.create_group(params)
+group1
+
+
Group(_requester=<canvasapi.requester.Requester object>, id=121649, name=Group01_SP23, created_at=2023-04-19T08:14:04Z, created_at_date=2023-04-19 08:14:04+00:00, max_membership=5, is_public=False, join_level=invitation_only, group_category_id=16167, description=None, members_count=0, storage_quota_mb=1024, storage_quota_mb_date=1024-01-01 00:00:00+00:00, permissions={'create_discussion_topic': True, 'join': False, 'create_announcement': True}, context_type=Course, course_id=45059, avatar_url=None, role=None, leader=None, users=[], group_category={'id': 16167, 'name': 'Final-Project_testing', 'role': None, 'self_signup': None, 'group_limit': 5, 'auto_leader': None, 'created_at': '2023-04-19T03:27:12Z', 'context_type': 'Course', 'course_id': 45059, 'protected': False, 'allows_multiple_memberships': False, 'is_member': False}, has_submission=False, concluded=False)
+
+
+
+
+
+

Assign Student to the Group

+
+

source

+
+

CanvasGroup.join_canvas_group

+
+
 CanvasGroup.join_canvas_group (group:canvasapi.group.Group,
+                                group_members:[<class'str'>])
+
+

Add membership access of each group member into the group

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDetails
groupGroupthe group that students will join
group_members[<class ‘str’>]list of group member’s SIS Login (email prefix, before the @.)
Returns[<class ‘str’>]list of unsuccessful join
+
+
member1 = "email"
+cg.join_canvas_group(group1, [member1])
+
+
[]
+
+
+ + +
+
+
+ +
+ +
+ + + + \ No newline at end of file diff --git a/_proc/_docs/clean_up.html b/_proc/_docs/clean_up.html new file mode 100644 index 0000000..f0fee8d --- /dev/null +++ b/_proc/_docs/clean_up.html @@ -0,0 +1,417 @@ + + + + + + + + + + +CanvasGroupy - Clean-up and Tear Down + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Clean-up and Tear Down

+
+ +
+
+ Keep your local computer fresh and clean, without 200+ students groups files. +
+
+ + +
+ + + + +
+ + +
+ + + + + +
+ +
+ + + + \ No newline at end of file diff --git a/_proc/_docs/core.html b/_proc/_docs/core.html index 3392f7d..493578e 100644 --- a/_proc/_docs/core.html +++ b/_proc/_docs/core.html @@ -2,7 +2,7 @@ - + @@ -18,9 +18,43 @@ ul.task-list{list-style: none;} ul.task-list li input[type="checkbox"] { width: 0.8em; - margin: 0 0.8em 0.2em -1.6em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ vertical-align: middle; } +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} @@ -81,47 +115,68 @@ CanvasGroupy +
+
-
-
-
-
-
-
-
-