making-with-code-cli 2.1.0__tar.gz → 2.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/PKG-INFO +5 -2
  2. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/curriculum.py +7 -4
  3. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/__init__.py +2 -2
  4. making_with_code_cli-2.2.1/making_with_code_cli/teach/check/__init__.py +44 -0
  5. making_with_code_cli-2.2.1/making_with_code_cli/teach/check/check_module.py +89 -0
  6. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/pyproject.toml +14 -2
  7. making_with_code_cli-2.1.0/making_with_code_cli/teach/check.py +0 -25
  8. making_with_code_cli-2.1.0/making_with_code_cli/teach/test/__init__.py +0 -14
  9. making_with_code_cli-2.1.0/making_with_code_cli/teach/test/test_module.py +0 -9
  10. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/README.md +0 -0
  11. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/cli.py +0 -0
  12. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/errors.py +0 -0
  13. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/git_backend/__init__.py +0 -0
  14. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/git_backend/base_backend.py +0 -0
  15. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/git_backend/mwc_backend.py +0 -0
  16. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/git_wrapper.py +0 -0
  17. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/helpers.py +0 -0
  18. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/mwc_accounts_api.py +0 -0
  19. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/settings.py +0 -0
  20. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/setup/__init__.py +0 -0
  21. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/setup/tasks.py +0 -0
  22. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/styles.py +0 -0
  23. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/submit.py +0 -0
  24. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/assess.py +0 -0
  25. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/gitea_api/api.py +0 -0
  26. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/gitea_api/exceptions.py +0 -0
  27. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/log.py +0 -0
  28. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/patch.py +0 -0
  29. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/setup.py +0 -0
  30. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/status.py +0 -0
  31. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/student_repo_functions.py +0 -0
  32. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/student_repos.py +0 -0
  33. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/teach/update.py +0 -0
  34. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/update/__init__.py +0 -0
  35. {making_with_code_cli-2.1.0 → making_with_code_cli-2.2.1}/making_with_code_cli/version.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: making-with-code-cli
3
- Version: 2.1.0
3
+ Version: 2.2.1
4
4
  Summary: Courseware for Making With Code
5
5
  Home-page: https://github.com/cproctor/making-with-code-courseware
6
6
  License: MIT
@@ -11,6 +11,8 @@ Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
14
16
  Requires-Dist: PyYAML (>=6.0,<7.0)
15
17
  Requires-Dist: click (>=8.0.3,<9.0.0)
16
18
  Requires-Dist: dateparser (>=1.1.8,<2.0.0)
@@ -18,6 +20,7 @@ Requires-Dist: gitpython (>=3.1.32,<4.0.0)
18
20
  Requires-Dist: requests (>=2.27.1,<3.0.0)
19
21
  Requires-Dist: tabulate (>=0.9.0,<0.10.0)
20
22
  Requires-Dist: toml (>=0.10.2,<0.11.0)
23
+ Requires-Dist: tqdm (>=4.67.1,<5.0.0)
21
24
  Project-URL: issues, https://github.com/cproctor/making-with-code-courseware/issues
22
25
  Description-Content-Type: text/markdown
23
26
 
@@ -7,7 +7,7 @@ from making_with_code_cli.errors import (
7
7
 
8
8
  LIVE_RELOAD = '<script src="/livereload.js?port=1024&amp;mindelay=10"></script>'
9
9
 
10
- def get_curriculum(mwc_site_url, course_name):
10
+ def get_curriculum(mwc_site_url, course_name=None):
11
11
  """Fetches curriculum metadata from the site url specified in settings.
12
12
  Returns the curriculum metadata for course_name.
13
13
  """
@@ -16,9 +16,12 @@ def get_curriculum(mwc_site_url, course_name):
16
16
  if response.ok:
17
17
  text = response.text.strip(LIVE_RELOAD)
18
18
  metadata = json.loads(text)
19
- for course in metadata["courses"]:
20
- if course["name"] == course_name:
21
- return course
19
+ if course_name:
20
+ for course in metadata["courses"]:
21
+ if course["name"] == course_name:
22
+ return course
23
+ else:
24
+ return metadata
22
25
  raise CurriculumNotFound(mwc_site_url, course_name)
23
26
  else:
24
27
  raise CurriculumSiteNotAvailable(mwc_site_url)
@@ -4,7 +4,7 @@ from making_with_code_cli.teach.update import update
4
4
  from making_with_code_cli.teach.status import status
5
5
  from making_with_code_cli.teach.log import log
6
6
  from making_with_code_cli.teach.patch import patch
7
- from making_with_code_cli.teach.test import test
7
+ from making_with_code_cli.teach.check import check
8
8
 
9
9
  @click.group()
10
10
  def teach():
@@ -15,4 +15,4 @@ teach.add_command(update)
15
15
  teach.add_command(status)
16
16
  teach.add_command(log)
17
17
  teach.add_command(patch)
18
- teach.add_command(test)
18
+ teach.add_command(check)
@@ -0,0 +1,44 @@
1
+ from textwrap import fill
2
+ import click
3
+ import requests
4
+ from pathlib import Path
5
+ from tqdm import tqdm
6
+ from making_with_code_cli.curriculum import get_curriculum
7
+ from making_with_code_cli.teach.check.check_module import TestMWCModule
8
+
9
+ @click.command()
10
+ @click.argument("url")
11
+ @click.argument("repo_dir", type=click.Path(exists=True, file_okay=False, writable=True,
12
+ path_type=Path))
13
+ @click.option("--course", "-c", help="Course name to check")
14
+ @click.option("--module", "-m", help="Module slug to check")
15
+ @click.option("--json", "-j", 'use_json', is_flag=True, help="JSON-structured output")
16
+ def check(url, repo_dir, course, module, use_json):
17
+ "Test MWC curriuclum and modules"
18
+ if course:
19
+ courses = [get_curriculum(url, course)]
20
+ else:
21
+ courses = get_curriculum(url)['courses']
22
+ test_cases = []
23
+ for course in courses:
24
+ for unit in course['units']:
25
+ for mod in unit['modules']:
26
+ if not module or mod['slug'] == module:
27
+ full_slug = '/'.join([course['slug'], unit['slug'], mod['slug']])
28
+ path = repo_dir / full_slug
29
+ test_cases.append((mod, path, full_slug))
30
+ results = []
31
+ if not module:
32
+ test_cases = tqdm(test_cases)
33
+ for mod, path, slug in test_cases:
34
+ test = TestMWCModule(mod, path)
35
+ errors = test.run()
36
+ if errors:
37
+ results.append((slug, errors))
38
+ if use_json:
39
+ print([{'module': slug, 'errors': errors} for slug, errors in results])
40
+ else:
41
+ for slug, errors in results:
42
+ print(slug)
43
+ for error in errors:
44
+ print(fill(error, width=80, initial_indent="- ", subsequent_indent=" "))
@@ -0,0 +1,89 @@
1
+ # test_module.py
2
+ # --------------
3
+ # Defines a test case for a MWC module.
4
+
5
+ from pathlib import Path
6
+ from subprocess import run
7
+ import requests
8
+ import toml
9
+ from git import Repo, InvalidGitRepositoryError, GitCommandError
10
+
11
+ DEFAULT_BRANCH_NAME = "main"
12
+ PYTHON_VERSION = ">=3.10"
13
+
14
+ class TestCouldNotContinue(Exception):
15
+ pass
16
+
17
+ class TestMWCModule:
18
+
19
+ def __init__(self, module_metadata, repo_path):
20
+ self.module_metadata = module_metadata
21
+ self.repo_path = repo_path
22
+
23
+ def run(self):
24
+ self.errors = []
25
+ try:
26
+ self.fetch_repo()
27
+ self.test_curriculum_page_exists()
28
+ self.test_has_commit_template()
29
+ self.test_poetry()
30
+ self.test_module_metadata()
31
+ except TestCouldNotContinue as err:
32
+ self.errors.append(str(err))
33
+ return self.errors
34
+
35
+ def fetch_repo(self):
36
+ """Ensures the repo is present and up to date.
37
+ """
38
+ if self.repo_path.exists():
39
+ try:
40
+ repo = Repo(self.repo_path)
41
+ repo.remotes.origin.pull()
42
+ except InvalidGitRepositoryError:
43
+ raise TestCouldNotContinue(f"{self.module_path} exists but is not a repo")
44
+ else:
45
+ try:
46
+ repo = Repo.clone_from(self.module_metadata['repo_url'], self.repo_path)
47
+ except GitCommandError:
48
+ raise TestCouldNotContinue("Could not clone repo")
49
+ if not repo.active_branch.name == DEFAULT_BRANCH_NAME:
50
+ self.errors.append(f"Default branch is not '{DEFAULT_BRANCH_NAME}'")
51
+
52
+ def test_curriculum_page_exists(self):
53
+ page_url = self.module_metadata['url']
54
+ response = requests.get(page_url)
55
+ if not response.ok:
56
+ self.errors.append(f"Curriculum page missing: {page_url}")
57
+
58
+ def test_has_commit_template(self):
59
+ ct = self.repo_path / ".commit_template"
60
+ if not ct.exists:
61
+ self.errors.append(".commit_template is missing")
62
+
63
+ def test_poetry(self):
64
+ result = run("poetry check", cwd=self.repo_path, shell=True, capture_output=True,
65
+ text=True)
66
+ if result.returncode:
67
+ for err in result.stderr.split('\n'):
68
+ if err.strip():
69
+ self.errors.append(err.strip())
70
+
71
+ def test_module_metadata(self):
72
+ md_file = self.repo_path/"pyproject.toml"
73
+ if not md_file.exists():
74
+ self.errors.append(f"pyproject.toml missing")
75
+ return
76
+ md = toml.load(md_file)
77
+ if not "project" in md:
78
+ self.errors.append("'project' section missing from pyproject.toml")
79
+ return
80
+ if "tool" in md:
81
+ self.errors.append("Deprecated 'tool' section found in pyproject.toml")
82
+ pyversion = md['project'].get('requires-python')
83
+ if not pyversion == PYTHON_VERSION:
84
+ self.errors.append(f"python version is {pyversion}, expected {PYTHON_VERSION}")
85
+
86
+
87
+
88
+
89
+
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "making-with-code-cli"
3
- version = "2.1.0"
3
+ version = "2.2.1"
4
4
  description = "Courseware for Making With Code"
5
5
  authors = ["Chris Proctor <chris@chrisproctor.net>"]
6
6
  license = "MIT"
@@ -16,8 +16,20 @@ toml = "^0.10.2"
16
16
  tabulate = "^0.9.0"
17
17
  gitpython = "^3.1.32"
18
18
  dateparser = "^1.1.8"
19
+ tqdm = "^4.67.1"
19
20
 
20
- [tool.poetry.dev-dependencies]
21
+ [tool.poetry.group.docs]
22
+ optional = true
23
+
24
+ [tool.poetry.group.docs.dependencies]
25
+ sphinx = "^7.3.7"
26
+ sphinx-rtd-theme = "^2.0.0"
27
+
28
+ [tool.poetry.group.teacher]
29
+ optional = true
30
+
31
+ [tool.poetry.group.teacher.dependencies]
32
+ gitpython = "^3.1.44"
21
33
 
22
34
  [build-system]
23
35
  requires = ["poetry-core>=1.0.0"]
@@ -1,25 +0,0 @@
1
- # Checks setup of
2
-
3
- # - Curriculum
4
- # - Check out each template directory
5
- # - Main branch?
6
- # - Has .commit_template?
7
- # - Is template?
8
-
9
- class MWCModuleTests:
10
-
11
- {'teacher_groups': [{'code': 'lai676',
12
- 'course_name': 'Making With Code I',
13
- 'curriculum_site_url': 'https://makingwithcode.org',
14
- 'group_name': 'LAI 676 Summer 2023',
15
- 'student_tokens': {'cchung': 'b6f7bbeb34a076c1da7c6a58c9d41e1c1faecb9e',
16
- 'finn': '320abfad1c97c78a274a66d1f7cbd651151d7f7d',
17
- 'jtoombs': 'aae00b2af1722517efadd5cfc58156696de9626c',
18
- 'kodell-hamilton': '66054d1f27ff7b793c3d19b96a1e207105938149',
19
- 'lcooper': '31d0d64ecb7182eef437fd33f8eeb7e45f4c32ad',
20
- 'mgunsolus': '1f9549e36f44fc710bac82153d972e41b0df2b0f',
21
- 'mhall': '8dbab4a23a988bbfab71ff96ee673a03224f90ac',
22
- 'pwick': '3e28563be3eba4e9fcd8e9d8ce5abb494fe27d94',
23
- 'test_user_lai676': '87bbf8e278b6fa5ead76467810f8e48d93b1b46e',
24
- 'tnaber': '00456bd8df3e513e787d113df8992d5c66475c3f'}}],
25
- 'username': 'chris'}
@@ -1,14 +0,0 @@
1
- import click
2
- from making_with_code_cli.teach.test.test_module import TestMWCModule
3
-
4
- @click.command()
5
- def test():
6
- "Test MWC curriuclum and modules"
7
-
8
- """
9
- """
10
- # - Curriculum
11
- # - Check out each template directory
12
- # - Main branch?
13
- # - Has .commit_template?
14
- # - Is template?
@@ -1,9 +0,0 @@
1
- # test_module.py
2
- # --------------
3
- # Defines a testcase for a MWC module.
4
-
5
- from unittest import TestCase
6
-
7
- class TestMWCModule:
8
- def __init__(self, module_path):
9
- self.module_path = module_path