scratchattach 2.1.14__tar.gz → 3.0.0b0__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.
- {scratchattach-2.1.14/scratchattach.egg-info → scratchattach-3.0.0b0}/PKG-INFO +7 -11
- scratchattach-3.0.0b0/pyproject.toml +95 -0
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/scratchattach/__init__.py +14 -6
- scratchattach-3.0.0b0/scratchattach/__main__.py +93 -0
- {scratchattach-2.1.14 → scratchattach-3.0.0b0/scratchattach.egg-info}/PKG-INFO +7 -11
- scratchattach-3.0.0b0/scratchattach.egg-info/SOURCES.txt +25 -0
- scratchattach-3.0.0b0/scratchattach.egg-info/entry_points.txt +2 -0
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/scratchattach.egg-info/requires.txt +5 -0
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_activity.py +7 -8
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_auth.py +2 -2
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_comment.py +25 -19
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_editor_integration.py +8 -8
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_editor_obfuscation.py +2 -5
- scratchattach-3.0.0b0/tests/test_editor_project.py +6 -0
- scratchattach-3.0.0b0/tests/test_import.py +5 -0
- scratchattach-3.0.0b0/tests/test_memberships.py +36 -0
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_other_apis.py +5 -8
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_project.py +15 -15
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_search.py +7 -5
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_studio.py +17 -12
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_teacher_activity.py +3 -6
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/tests/test_user.py +34 -20
- scratchattach-2.1.14/MANIFEST.in +0 -1
- scratchattach-2.1.14/requirements.txt +0 -6
- scratchattach-2.1.14/scratchattach/cloud/__init__.py +0 -2
- scratchattach-2.1.14/scratchattach/cloud/_base.py +0 -458
- scratchattach-2.1.14/scratchattach/cloud/cloud.py +0 -183
- scratchattach-2.1.14/scratchattach/editor/__init__.py +0 -21
- scratchattach-2.1.14/scratchattach/editor/asset.py +0 -253
- scratchattach-2.1.14/scratchattach/editor/backpack_json.py +0 -117
- scratchattach-2.1.14/scratchattach/editor/base.py +0 -193
- scratchattach-2.1.14/scratchattach/editor/block.py +0 -579
- scratchattach-2.1.14/scratchattach/editor/blockshape.py +0 -357
- scratchattach-2.1.14/scratchattach/editor/build_defaulting.py +0 -51
- scratchattach-2.1.14/scratchattach/editor/code_translation/__init__.py +0 -0
- scratchattach-2.1.14/scratchattach/editor/code_translation/parse.py +0 -177
- scratchattach-2.1.14/scratchattach/editor/comment.py +0 -80
- scratchattach-2.1.14/scratchattach/editor/commons.py +0 -306
- scratchattach-2.1.14/scratchattach/editor/extension.py +0 -50
- scratchattach-2.1.14/scratchattach/editor/field.py +0 -99
- scratchattach-2.1.14/scratchattach/editor/inputs.py +0 -135
- scratchattach-2.1.14/scratchattach/editor/meta.py +0 -114
- scratchattach-2.1.14/scratchattach/editor/monitor.py +0 -183
- scratchattach-2.1.14/scratchattach/editor/mutation.py +0 -324
- scratchattach-2.1.14/scratchattach/editor/pallete.py +0 -90
- scratchattach-2.1.14/scratchattach/editor/prim.py +0 -170
- scratchattach-2.1.14/scratchattach/editor/project.py +0 -279
- scratchattach-2.1.14/scratchattach/editor/sprite.py +0 -599
- scratchattach-2.1.14/scratchattach/editor/twconfig.py +0 -114
- scratchattach-2.1.14/scratchattach/editor/vlb.py +0 -134
- scratchattach-2.1.14/scratchattach/eventhandlers/__init__.py +0 -0
- scratchattach-2.1.14/scratchattach/eventhandlers/_base.py +0 -100
- scratchattach-2.1.14/scratchattach/eventhandlers/cloud_events.py +0 -110
- scratchattach-2.1.14/scratchattach/eventhandlers/cloud_recorder.py +0 -26
- scratchattach-2.1.14/scratchattach/eventhandlers/cloud_requests.py +0 -459
- scratchattach-2.1.14/scratchattach/eventhandlers/cloud_server.py +0 -246
- scratchattach-2.1.14/scratchattach/eventhandlers/cloud_storage.py +0 -136
- scratchattach-2.1.14/scratchattach/eventhandlers/combine.py +0 -30
- scratchattach-2.1.14/scratchattach/eventhandlers/filterbot.py +0 -161
- scratchattach-2.1.14/scratchattach/eventhandlers/message_events.py +0 -42
- scratchattach-2.1.14/scratchattach/other/__init__.py +0 -0
- scratchattach-2.1.14/scratchattach/other/other_apis.py +0 -284
- scratchattach-2.1.14/scratchattach/other/project_json_capabilities.py +0 -475
- scratchattach-2.1.14/scratchattach/site/__init__.py +0 -0
- scratchattach-2.1.14/scratchattach/site/_base.py +0 -66
- scratchattach-2.1.14/scratchattach/site/activity.py +0 -382
- scratchattach-2.1.14/scratchattach/site/alert.py +0 -227
- scratchattach-2.1.14/scratchattach/site/backpack_asset.py +0 -118
- scratchattach-2.1.14/scratchattach/site/browser_cookie3_stub.py +0 -17
- scratchattach-2.1.14/scratchattach/site/browser_cookies.py +0 -61
- scratchattach-2.1.14/scratchattach/site/classroom.py +0 -447
- scratchattach-2.1.14/scratchattach/site/cloud_activity.py +0 -107
- scratchattach-2.1.14/scratchattach/site/comment.py +0 -242
- scratchattach-2.1.14/scratchattach/site/forum.py +0 -432
- scratchattach-2.1.14/scratchattach/site/project.py +0 -825
- scratchattach-2.1.14/scratchattach/site/session.py +0 -1238
- scratchattach-2.1.14/scratchattach/site/studio.py +0 -611
- scratchattach-2.1.14/scratchattach/site/user.py +0 -956
- scratchattach-2.1.14/scratchattach/utils/__init__.py +0 -0
- scratchattach-2.1.14/scratchattach/utils/commons.py +0 -255
- scratchattach-2.1.14/scratchattach/utils/encoder.py +0 -158
- scratchattach-2.1.14/scratchattach/utils/enums.py +0 -236
- scratchattach-2.1.14/scratchattach/utils/exceptions.py +0 -243
- scratchattach-2.1.14/scratchattach/utils/requests.py +0 -93
- scratchattach-2.1.14/scratchattach.egg-info/SOURCES.txt +0 -84
- scratchattach-2.1.14/setup.py +0 -40
- scratchattach-2.1.14/tests/test_editor_project.py +0 -9
- scratchattach-2.1.14/tests/test_import.py +0 -4
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/LICENSE +0 -0
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/README.md +0 -0
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/scratchattach.egg-info/dependency_links.txt +0 -0
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/scratchattach.egg-info/top_level.txt +0 -0
- {scratchattach-2.1.14 → scratchattach-3.0.0b0}/setup.cfg +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scratchattach
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0b0
|
|
4
4
|
Summary: A Scratch API Wrapper
|
|
5
5
|
Author: TimMcCool
|
|
6
|
-
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Source, https://github.com/timmccool/scratchattach
|
|
8
8
|
Project-URL: Homepage, https://scratchattach.tim1de.net
|
|
9
9
|
Keywords: scratch api,scratchattach,scratch api python,scratch python,scratch for python,scratch,scratch cloud,scratch cloud variables,scratch bot
|
|
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
13
13
|
Classifier: Operating System :: Unix
|
|
14
14
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
15
15
|
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Requires-Python: >=3.12
|
|
16
17
|
Description-Content-Type: text/markdown
|
|
17
18
|
License-File: LICENSE
|
|
18
19
|
Requires-Dist: websocket-client
|
|
@@ -21,18 +22,13 @@ Requires-Dist: bs4
|
|
|
21
22
|
Requires-Dist: SimpleWebSocketServer
|
|
22
23
|
Requires-Dist: typing-extensions
|
|
23
24
|
Requires-Dist: browser_cookie3
|
|
25
|
+
Requires-Dist: aiohttp
|
|
26
|
+
Requires-Dist: rich
|
|
27
|
+
Provides-Extra: cli
|
|
28
|
+
Requires-Dist: rich-pixels; extra == "cli"
|
|
24
29
|
Provides-Extra: lark
|
|
25
30
|
Requires-Dist: lark; extra == "lark"
|
|
26
|
-
Dynamic: author
|
|
27
|
-
Dynamic: classifier
|
|
28
|
-
Dynamic: description
|
|
29
|
-
Dynamic: description-content-type
|
|
30
|
-
Dynamic: keywords
|
|
31
31
|
Dynamic: license-file
|
|
32
|
-
Dynamic: project-url
|
|
33
|
-
Dynamic: provides-extra
|
|
34
|
-
Dynamic: requires-dist
|
|
35
|
-
Dynamic: summary
|
|
36
32
|
|
|
37
33
|
**scratchattach is a Scratch API wrapper with support for almost all site features.** Created by [TimMcCool](https://scratch.mit.edu/users/TimMcCool/).
|
|
38
34
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools >= 77.0.3"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "scratchattach"
|
|
7
|
+
version = "3.0.0b0"
|
|
8
|
+
authors = [{ name = "TimMcCool" }]
|
|
9
|
+
description = "A Scratch API Wrapper"
|
|
10
|
+
requires-python = ">= 3.12"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"websocket-client",
|
|
13
|
+
"requests",
|
|
14
|
+
"bs4",
|
|
15
|
+
"SimpleWebSocketServer",
|
|
16
|
+
"typing-extensions",
|
|
17
|
+
"browser_cookie3",
|
|
18
|
+
"aiohttp",
|
|
19
|
+
"rich",
|
|
20
|
+
]
|
|
21
|
+
readme = "README.md"
|
|
22
|
+
license = "MIT"
|
|
23
|
+
license-files = ["LICENSE"]
|
|
24
|
+
keywords = [
|
|
25
|
+
"scratch api",
|
|
26
|
+
"scratchattach",
|
|
27
|
+
"scratch api python",
|
|
28
|
+
"scratch python",
|
|
29
|
+
"scratch for python",
|
|
30
|
+
"scratch",
|
|
31
|
+
"scratch cloud",
|
|
32
|
+
"scratch cloud variables",
|
|
33
|
+
"scratch bot",
|
|
34
|
+
]
|
|
35
|
+
classifiers = [
|
|
36
|
+
"Development Status :: 5 - Production/Stable",
|
|
37
|
+
"Intended Audience :: Developers",
|
|
38
|
+
"Programming Language :: Python :: 3",
|
|
39
|
+
"Operating System :: Unix",
|
|
40
|
+
"Operating System :: MacOS :: MacOS X",
|
|
41
|
+
"Operating System :: Microsoft :: Windows",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Source = "https://github.com/timmccool/scratchattach"
|
|
46
|
+
Homepage = "https://scratchattach.tim1de.net"
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
scratch = "scratchattach.__main__:main"
|
|
50
|
+
|
|
51
|
+
[project.optional-dependencies]
|
|
52
|
+
cli = ["rich-pixels"]
|
|
53
|
+
lark = ["lark"]
|
|
54
|
+
|
|
55
|
+
[tool.ruff]
|
|
56
|
+
line-length = 127
|
|
57
|
+
exclude = [
|
|
58
|
+
".bzr",
|
|
59
|
+
".direnv",
|
|
60
|
+
".eggs",
|
|
61
|
+
".git",
|
|
62
|
+
".git-rewrite",
|
|
63
|
+
".hg",
|
|
64
|
+
".ipynb_checkpoints",
|
|
65
|
+
".mypy_cache",
|
|
66
|
+
".nox",
|
|
67
|
+
".pants.d",
|
|
68
|
+
".pyenv",
|
|
69
|
+
".pytest_cache",
|
|
70
|
+
".pytype",
|
|
71
|
+
".ruff_cache",
|
|
72
|
+
".svn",
|
|
73
|
+
".tox",
|
|
74
|
+
".venv",
|
|
75
|
+
".vscode",
|
|
76
|
+
"__pypackages__",
|
|
77
|
+
"_build",
|
|
78
|
+
"buck-out",
|
|
79
|
+
"build",
|
|
80
|
+
"dist",
|
|
81
|
+
"node_modules",
|
|
82
|
+
"site-packages",
|
|
83
|
+
"venv",
|
|
84
|
+
]
|
|
85
|
+
[tool.ruff.lint]
|
|
86
|
+
select = ["E9", "F63", "F7", "F82"] # , "C901"] # uncomment to re-enable mccabe complexity - see https://github.com/TimMcCool/scratchattach/issues/566
|
|
87
|
+
|
|
88
|
+
[tool.ruff.lint.mccabe]
|
|
89
|
+
# max-complexity = 10
|
|
90
|
+
|
|
91
|
+
[tool.setuptools.packages]
|
|
92
|
+
find = { include = ["scratchattach"] }
|
|
93
|
+
|
|
94
|
+
[dependency-groups]
|
|
95
|
+
dev = ["cryptography>=46.0.3", "pytest>=9.0.2"]
|
|
@@ -8,22 +8,30 @@ from .eventhandlers.cloud_storage import Database
|
|
|
8
8
|
from .eventhandlers.combine import MultiEventHandler
|
|
9
9
|
|
|
10
10
|
from .other.other_apis import *
|
|
11
|
-
from .other.project_json_capabilities import ProjectBody, get_empty_project_pb, get_pb_from_dict, read_sb3_file, download_asset
|
|
11
|
+
# from .other.project_json_capabilities import ProjectBody, get_empty_project_pb, get_pb_from_dict, read_sb3_file, download_asset
|
|
12
12
|
from .utils.encoder import Encoding
|
|
13
13
|
from .utils.enums import Languages, TTSVoices
|
|
14
|
-
from .utils.exceptions import
|
|
14
|
+
from .utils.exceptions import (
|
|
15
|
+
LoginDataWarning,
|
|
16
|
+
GetAuthenticationWarning,
|
|
17
|
+
StudioAuthenticationWarning,
|
|
18
|
+
ClassroomAuthenticationWarning,
|
|
19
|
+
ProjectAuthenticationWarning,
|
|
20
|
+
UserAuthenticationWarning)
|
|
15
21
|
|
|
16
|
-
from .site.activity import Activity
|
|
22
|
+
from .site.activity import Activity, ActivityTypes
|
|
17
23
|
from .site.backpack_asset import BackpackAsset
|
|
18
|
-
from .site.comment import Comment
|
|
24
|
+
from .site.comment import Comment, CommentSource
|
|
19
25
|
from .site.cloud_activity import CloudActivity
|
|
20
26
|
from .site.forum import ForumPost, ForumTopic, get_topic, get_topic_list, youtube_link_to_scratch
|
|
21
27
|
from .site.project import Project, get_project, search_projects, explore_projects
|
|
22
|
-
from .site.session import Session, login, login_by_id, login_by_session_string, login_by_io, login_by_file,
|
|
28
|
+
from .site.session import Session, login, login_by_id, login_by_session_string, login_by_io, login_by_file, \
|
|
29
|
+
login_from_browser
|
|
23
30
|
from .site.studio import Studio, get_studio, search_studios, explore_studios
|
|
24
31
|
from .site.classroom import Classroom, get_classroom
|
|
25
|
-
from .site.user import User, get_user
|
|
32
|
+
from .site.user import User, get_user, Rank
|
|
26
33
|
from .site._base import BaseSiteComponent
|
|
27
34
|
from .site.browser_cookies import Browser, ANY, FIREFOX, CHROME, CHROMIUM, VIVALDI, EDGE, EDGE_DEV, SAFARI
|
|
35
|
+
from .site.placeholder import PlaceholderProject, get_placeholder_project, create_placeholder_project
|
|
28
36
|
|
|
29
37
|
from . import editor
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Scratchattach CLI. Most source code is in the `cli` directory
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
|
|
7
|
+
from scratchattach import cli
|
|
8
|
+
from scratchattach.cli import db, cmd
|
|
9
|
+
from scratchattach.cli.context import ctx, console
|
|
10
|
+
|
|
11
|
+
import rich.traceback
|
|
12
|
+
|
|
13
|
+
rich.traceback.install()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# noinspection PyUnusedLocal
|
|
17
|
+
def main():
|
|
18
|
+
parser = argparse.ArgumentParser(
|
|
19
|
+
prog="scratch",
|
|
20
|
+
description="Scratchattach CLI",
|
|
21
|
+
epilog=f"Running scratchattach CLI version {cli.VERSION}",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Using walrus operator & ifs for artificial indentation
|
|
25
|
+
if commands := parser.add_subparsers(dest="command"):
|
|
26
|
+
commands.add_parser("profile", help="View your profile")
|
|
27
|
+
commands.add_parser("sessions", help="View session list")
|
|
28
|
+
if login := commands.add_parser("login", help="Login to Scratch"):
|
|
29
|
+
login.add_argument("--sessid", dest="sessid", nargs="?", default=False, const=True,
|
|
30
|
+
help="Login by session ID")
|
|
31
|
+
if group := commands.add_parser("group", help="View current session group"):
|
|
32
|
+
if group_commands := group.add_subparsers(dest="group_command"):
|
|
33
|
+
group_commands.add_parser("list", help="List all session groups")
|
|
34
|
+
group_commands.add_parser("add", help="Add sessions to group")
|
|
35
|
+
group_commands.add_parser("remove", help="Remove sessions from a group")
|
|
36
|
+
group_commands.add_parser("delete", help="Delete current group")
|
|
37
|
+
if group_copy := group_commands.add_parser("copy", help="Copy current group with a new name"):
|
|
38
|
+
group_copy.add_argument("group_name", help="New group name")
|
|
39
|
+
if group_rename := group_commands.add_parser("rename", help="Rename current group"):
|
|
40
|
+
group_rename.add_argument("group_name", help="New group name")
|
|
41
|
+
if group_new := group_commands.add_parser("new", help="Create a new group"):
|
|
42
|
+
group_new.add_argument("group_name")
|
|
43
|
+
if group_switch := group_commands.add_parser("switch", help="Change the current group"):
|
|
44
|
+
group_switch.add_argument("group_name")
|
|
45
|
+
|
|
46
|
+
parser.add_argument("-U", "--username", dest="username", help="Name of user to look at")
|
|
47
|
+
parser.add_argument("-P", "--project", dest="project_id", help="ID of project to look at")
|
|
48
|
+
parser.add_argument("-S", "--studio", dest="studio_id", help="ID of studio to look at")
|
|
49
|
+
parser.add_argument("-L", "--session_name", dest="session_name",
|
|
50
|
+
help="Name of (registered) session/login to look at")
|
|
51
|
+
|
|
52
|
+
args = parser.parse_args(namespace=cli.ArgSpace())
|
|
53
|
+
cli.ctx.args = args
|
|
54
|
+
cli.ctx.parser = parser
|
|
55
|
+
|
|
56
|
+
match args.command:
|
|
57
|
+
case "sessions":
|
|
58
|
+
cmd.sessions()
|
|
59
|
+
case "login":
|
|
60
|
+
cmd.login()
|
|
61
|
+
case "group":
|
|
62
|
+
cmd.group()
|
|
63
|
+
case "profile":
|
|
64
|
+
cmd.profile()
|
|
65
|
+
case None:
|
|
66
|
+
if args.username:
|
|
67
|
+
user = ctx.session.connect_user(args.username)
|
|
68
|
+
console.print(cli.try_get_img(user.icon, (30, 30)))
|
|
69
|
+
console.print(user)
|
|
70
|
+
return
|
|
71
|
+
if args.studio_id:
|
|
72
|
+
studio = ctx.session.connect_studio(args.studio_id)
|
|
73
|
+
console.print(cli.try_get_img(studio.thumbnail, (34, 20)))
|
|
74
|
+
console.print(studio)
|
|
75
|
+
return
|
|
76
|
+
if args.project_id:
|
|
77
|
+
project = ctx.session.connect_project(args.project_id)
|
|
78
|
+
console.print(cli.try_get_img(project.thumbnail, (30, 23)))
|
|
79
|
+
console.print(project)
|
|
80
|
+
return
|
|
81
|
+
if args.session_name:
|
|
82
|
+
if sess := ctx.db_get_sess(args.session_name):
|
|
83
|
+
console.print(sess)
|
|
84
|
+
else:
|
|
85
|
+
raise ValueError(f"No session logged in called {args.session_name!r} "
|
|
86
|
+
f"- try using `scratch sessions` to see available sessions")
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
parser.print_help()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
if __name__ == '__main__':
|
|
93
|
+
main()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scratchattach
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0b0
|
|
4
4
|
Summary: A Scratch API Wrapper
|
|
5
5
|
Author: TimMcCool
|
|
6
|
-
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Source, https://github.com/timmccool/scratchattach
|
|
8
8
|
Project-URL: Homepage, https://scratchattach.tim1de.net
|
|
9
9
|
Keywords: scratch api,scratchattach,scratch api python,scratch python,scratch for python,scratch,scratch cloud,scratch cloud variables,scratch bot
|
|
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
13
13
|
Classifier: Operating System :: Unix
|
|
14
14
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
15
15
|
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Requires-Python: >=3.12
|
|
16
17
|
Description-Content-Type: text/markdown
|
|
17
18
|
License-File: LICENSE
|
|
18
19
|
Requires-Dist: websocket-client
|
|
@@ -21,18 +22,13 @@ Requires-Dist: bs4
|
|
|
21
22
|
Requires-Dist: SimpleWebSocketServer
|
|
22
23
|
Requires-Dist: typing-extensions
|
|
23
24
|
Requires-Dist: browser_cookie3
|
|
25
|
+
Requires-Dist: aiohttp
|
|
26
|
+
Requires-Dist: rich
|
|
27
|
+
Provides-Extra: cli
|
|
28
|
+
Requires-Dist: rich-pixels; extra == "cli"
|
|
24
29
|
Provides-Extra: lark
|
|
25
30
|
Requires-Dist: lark; extra == "lark"
|
|
26
|
-
Dynamic: author
|
|
27
|
-
Dynamic: classifier
|
|
28
|
-
Dynamic: description
|
|
29
|
-
Dynamic: description-content-type
|
|
30
|
-
Dynamic: keywords
|
|
31
31
|
Dynamic: license-file
|
|
32
|
-
Dynamic: project-url
|
|
33
|
-
Dynamic: provides-extra
|
|
34
|
-
Dynamic: requires-dist
|
|
35
|
-
Dynamic: summary
|
|
36
32
|
|
|
37
33
|
**scratchattach is a Scratch API wrapper with support for almost all site features.** Created by [TimMcCool](https://scratch.mit.edu/users/TimMcCool/).
|
|
38
34
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
scratchattach/__init__.py
|
|
5
|
+
scratchattach/__main__.py
|
|
6
|
+
scratchattach.egg-info/PKG-INFO
|
|
7
|
+
scratchattach.egg-info/SOURCES.txt
|
|
8
|
+
scratchattach.egg-info/dependency_links.txt
|
|
9
|
+
scratchattach.egg-info/entry_points.txt
|
|
10
|
+
scratchattach.egg-info/requires.txt
|
|
11
|
+
scratchattach.egg-info/top_level.txt
|
|
12
|
+
tests/test_activity.py
|
|
13
|
+
tests/test_auth.py
|
|
14
|
+
tests/test_comment.py
|
|
15
|
+
tests/test_editor_integration.py
|
|
16
|
+
tests/test_editor_obfuscation.py
|
|
17
|
+
tests/test_editor_project.py
|
|
18
|
+
tests/test_import.py
|
|
19
|
+
tests/test_memberships.py
|
|
20
|
+
tests/test_other_apis.py
|
|
21
|
+
tests/test_project.py
|
|
22
|
+
tests/test_search.py
|
|
23
|
+
tests/test_studio.py
|
|
24
|
+
tests/test_teacher_activity.py
|
|
25
|
+
tests/test_user.py
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import sys
|
|
2
1
|
from datetime import datetime, timedelta, timezone
|
|
3
2
|
import warnings
|
|
4
|
-
|
|
3
|
+
import scratchattach as sa
|
|
4
|
+
from scratchattach.utils import exceptions
|
|
5
|
+
import util
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def test_activity():
|
|
8
|
-
sys.path.insert(0, ".")
|
|
9
|
-
import scratchattach as sa
|
|
10
|
-
from scratchattach.utils import exceptions
|
|
11
|
-
import util
|
|
12
9
|
if not util.credentials_available():
|
|
13
|
-
warnings.warn(
|
|
10
|
+
warnings.warn(
|
|
11
|
+
"Skipped test_activity because there were no credentials available."
|
|
12
|
+
)
|
|
14
13
|
return
|
|
15
14
|
sess = util.session()
|
|
16
15
|
|
|
17
16
|
# we cannot do assertions, but we can probe for any errors.
|
|
18
17
|
messages = sess.messages()
|
|
19
18
|
for msg in messages:
|
|
20
|
-
print(msg, end=
|
|
19
|
+
print(msg, end=" ")
|
|
21
20
|
|
|
22
21
|
try:
|
|
23
22
|
target = msg.target()
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import sys
|
|
2
1
|
from datetime import datetime, timedelta, timezone
|
|
3
2
|
import warnings
|
|
3
|
+
import scratchattach as sa
|
|
4
|
+
import util
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
def test_comment():
|
|
6
|
-
sys.path.insert(0, ".")
|
|
7
|
-
import scratchattach as sa
|
|
8
|
-
import util
|
|
9
8
|
if not util.credentials_available():
|
|
10
|
-
warnings.warn(
|
|
9
|
+
warnings.warn(
|
|
10
|
+
"Skipped test_comment because there were no credentials available."
|
|
11
|
+
)
|
|
11
12
|
return
|
|
12
13
|
sess = util.session()
|
|
13
14
|
|
|
@@ -18,37 +19,39 @@ def test_comment():
|
|
|
18
19
|
comment = user.comments(limit=1)[0]
|
|
19
20
|
|
|
20
21
|
assert comment.id == "387076703"
|
|
21
|
-
|
|
22
|
+
assert comment.source == sa.CommentSource.USER_PROFILE
|
|
22
23
|
assert comment.source_id == "ScratchAttachV2"
|
|
23
24
|
assert comment.parent_id is None
|
|
24
25
|
assert comment.content == "Sample comment"
|
|
25
|
-
assert datetime.fromisoformat(comment.datetime_created) - datetime(
|
|
26
|
+
assert datetime.fromisoformat(comment.datetime_created) - datetime(
|
|
27
|
+
2025, 8, 25, tzinfo=timezone.utc
|
|
28
|
+
) < timedelta(days=1)
|
|
26
29
|
assert comment.reply_count == 0
|
|
27
30
|
assert comment.text == "Sample comment"
|
|
28
31
|
|
|
29
32
|
comment = proj.comments(limit=1)[0]
|
|
30
33
|
|
|
31
34
|
assert comment.id == 494890468
|
|
32
|
-
|
|
35
|
+
assert comment.source == sa.CommentSource.PROJECT
|
|
33
36
|
assert comment.source_id == 1108326850
|
|
34
37
|
assert comment.parent_id is None
|
|
35
|
-
assert comment.content == ("<&;'!\n"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
assert comment.content == ("<&;'!\n" "newline\n" "testing escaping")
|
|
39
|
+
assert datetime.fromisoformat(comment.datetime_created) - datetime(
|
|
40
|
+
2025, 9, 20, tzinfo=timezone.utc
|
|
41
|
+
) < timedelta(days=1)
|
|
39
42
|
assert comment.reply_count == 0
|
|
40
|
-
assert comment.text == ("<&;'!\n"
|
|
41
|
-
"newline\n"
|
|
42
|
-
"testing escaping")
|
|
43
|
+
assert comment.text == ("<&;'!\n" "newline\n" "testing escaping")
|
|
43
44
|
|
|
44
45
|
comment = studio.comments(limit=1)[0]
|
|
45
46
|
|
|
46
47
|
assert comment.id == 302129887
|
|
47
|
-
|
|
48
|
+
assert comment.source == sa.CommentSource.STUDIO
|
|
48
49
|
assert comment.source_id == 50809872
|
|
49
50
|
assert comment.parent_id is None
|
|
50
51
|
assert comment.content == "Sample"
|
|
51
|
-
assert datetime.fromisoformat(comment.datetime_created) - datetime(
|
|
52
|
+
assert datetime.fromisoformat(comment.datetime_created) - datetime(
|
|
53
|
+
2025, 8, 26, tzinfo=timezone.utc
|
|
54
|
+
) < timedelta(days=1)
|
|
52
55
|
assert comment.reply_count == 1
|
|
53
56
|
assert not comment.written_by_scratchteam
|
|
54
57
|
assert comment.text == "Sample"
|
|
@@ -56,15 +59,18 @@ def test_comment():
|
|
|
56
59
|
comment = comment.replies(limit=1)[0]
|
|
57
60
|
|
|
58
61
|
assert comment.id == 302129910
|
|
59
|
-
|
|
62
|
+
assert comment.source == sa.CommentSource.STUDIO
|
|
60
63
|
assert comment.source_id == 50809872
|
|
61
64
|
assert comment.parent_id == 302129887
|
|
62
65
|
assert comment.commentee_id == 58743127
|
|
63
66
|
assert comment.content == "text"
|
|
64
|
-
assert datetime.fromisoformat(comment.datetime_created) - datetime(
|
|
67
|
+
assert datetime.fromisoformat(comment.datetime_created) - datetime(
|
|
68
|
+
2025, 8, 26, tzinfo=timezone.utc
|
|
69
|
+
) < timedelta(days=1)
|
|
65
70
|
assert comment.reply_count == 0
|
|
66
71
|
assert not comment.written_by_scratchteam
|
|
67
72
|
assert comment.text == "text"
|
|
68
73
|
|
|
74
|
+
|
|
69
75
|
if __name__ == "__main__":
|
|
70
76
|
test_comment()
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import pprint
|
|
2
|
-
import sys
|
|
3
2
|
import warnings
|
|
3
|
+
import util
|
|
4
|
+
import scratchattach as sa
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
def test_project():
|
|
6
|
-
sys.path.insert(0, ".")
|
|
7
|
-
import scratchattach as sa
|
|
8
|
-
import util
|
|
9
8
|
if not util.credentials_available():
|
|
10
|
-
warnings.warn(
|
|
9
|
+
warnings.warn(
|
|
10
|
+
"Skipped test_project because there were no credentials available."
|
|
11
|
+
)
|
|
11
12
|
return
|
|
12
13
|
sess = util.session()
|
|
13
14
|
|
|
14
|
-
|
|
15
15
|
project = sess.connect_project(104)
|
|
16
16
|
body = project.body()
|
|
17
17
|
body.to_json() # do nothing with the data, just make sure it works.
|
|
18
18
|
|
|
19
19
|
|
|
20
|
+
if __name__ == "__main__":
|
|
21
|
+
test_project()
|
|
20
22
|
|
|
21
|
-
if __name__ == '__main__':
|
|
22
|
-
test_project()
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import pprint
|
|
2
|
-
import sys
|
|
3
2
|
from pathlib import Path
|
|
3
|
+
import scratchattach as sa
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def test_project():
|
|
7
|
-
return
|
|
8
|
-
sys.path.insert(0, ".")
|
|
9
|
-
import scratchattach as sa
|
|
10
7
|
|
|
11
8
|
path = Path(__file__).parent.parent / "intro for kelmare (yoda tour) (p2).sb3"
|
|
12
9
|
|
|
@@ -24,5 +21,5 @@ def test_project():
|
|
|
24
21
|
body.export("obfuscated.sb3")
|
|
25
22
|
|
|
26
23
|
|
|
27
|
-
if __name__ ==
|
|
24
|
+
if __name__ == "__main__":
|
|
28
25
|
test_project()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import scratchattach as sa
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
4
|
+
warnings.filterwarnings("ignore", category=sa.UserAuthenticationWarning)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_memberships():
|
|
8
|
+
# unfortunately we don't have amazingly robust test-cases here.
|
|
9
|
+
u1 = sa.get_user("-KittyMax-")
|
|
10
|
+
assert u1.is_member
|
|
11
|
+
assert u1.has_ears
|
|
12
|
+
assert u1.has_badge()
|
|
13
|
+
|
|
14
|
+
u2 = sa.get_user("ceebee")
|
|
15
|
+
assert u2.is_member
|
|
16
|
+
assert u2.has_ears
|
|
17
|
+
assert u2.has_badge()
|
|
18
|
+
|
|
19
|
+
u3 = sa.get_user("scratchattachv2")
|
|
20
|
+
assert not u3.is_member
|
|
21
|
+
assert not u3.has_ears
|
|
22
|
+
assert not u3.has_badge()
|
|
23
|
+
|
|
24
|
+
u4 = sa.get_user("peekir")
|
|
25
|
+
assert u4.is_member
|
|
26
|
+
assert u4.has_ears
|
|
27
|
+
assert u4.has_badge()
|
|
28
|
+
|
|
29
|
+
u5 = sa.get_user("StardreamT2")
|
|
30
|
+
assert u5.is_member
|
|
31
|
+
assert u5.has_ears
|
|
32
|
+
assert not u5.has_badge()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
test_memberships()
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import pprint
|
|
2
|
-
import sys
|
|
3
2
|
from datetime import datetime, timedelta, timezone
|
|
4
3
|
import warnings
|
|
4
|
+
import scratchattach as sa
|
|
5
|
+
from scratchattach.utils import exceptions
|
|
6
|
+
import util
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
def test_other_apis():
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from scratchattach.utils import exceptions
|
|
11
|
-
import util
|
|
12
|
-
|
|
13
|
-
#assert sa.check_email("example@example.com")
|
|
14
|
-
#assert not sa.check_email("bad_email")
|
|
10
|
+
assert sa.check_email("example@example.com")
|
|
11
|
+
assert not sa.check_email("bad_email")
|
|
15
12
|
|
|
16
13
|
news = sa.get_news()
|
|
17
14
|
found_wiki_wednesday = False
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import pprint
|
|
2
|
-
import sys
|
|
3
1
|
import warnings
|
|
2
|
+
from util import session, credentials_available
|
|
3
|
+
import scratchattach as sa
|
|
4
|
+
|
|
4
5
|
|
|
5
6
|
def test_project():
|
|
6
|
-
sys.path.insert(0, ".")
|
|
7
|
-
import scratchattach as sa
|
|
8
|
-
from util import session, credentials_available
|
|
9
7
|
if not credentials_available():
|
|
10
|
-
warnings.warn(
|
|
8
|
+
warnings.warn(
|
|
9
|
+
"Skipped test_project because there were no credentials available."
|
|
10
|
+
)
|
|
11
11
|
return
|
|
12
12
|
sess = session()
|
|
13
13
|
|
|
14
|
-
|
|
15
14
|
project = sess.connect_project(104)
|
|
16
|
-
#tree = project.remix_tree_pretty()
|
|
17
|
-
#assert len(tree) > 1000 # there is a lot of chars. Just assert that sth is generated
|
|
15
|
+
# tree = project.remix_tree_pretty()
|
|
16
|
+
# assert len(tree) > 1000 # there is a lot of chars. Just assert that sth is generated
|
|
18
17
|
|
|
19
18
|
project = sess.connect_project(1209355136)
|
|
20
19
|
|
|
@@ -59,14 +58,15 @@ def test_project():
|
|
|
59
58
|
assert remix.author_name == "ScratchAttachV2"
|
|
60
59
|
assert remix.embed_url == "https://scratch.mit.edu/projects/1209582809/embed"
|
|
61
60
|
|
|
62
|
-
#assert sess.connect_project(414601586).moderation_status() == "notsafe"
|
|
63
|
-
#assert sess.connect_project(1207314193).moderation_status() == "safe"
|
|
64
|
-
#assert sess.connect_project(
|
|
65
|
-
#
|
|
61
|
+
# assert sess.connect_project(414601586).moderation_status() == "notsafe"
|
|
62
|
+
# assert sess.connect_project(1207314193).moderation_status() == "safe"
|
|
63
|
+
# assert sess.connect_project(
|
|
64
|
+
# 1233).moderation_status() == "notreviewed" # if this becomes reviewed, please update this
|
|
66
65
|
# ^^ also this project is an infinite remix loop!
|
|
67
66
|
|
|
68
67
|
assert sa.explore_projects()
|
|
69
68
|
assert sa.search_projects(query="scratchattach")
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
|
|
71
|
+
if __name__ == "__main__":
|
|
72
|
+
test_project()
|