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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions scratchattach/site/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,29 @@ def is_followed_by(self, user):
return followed
return followed

def is_followed_by_me(self):
"""
You can only use this function if this object was created using :meth:`scratchattach.session.Session.connect_user`

Returns:
boolean: Whether the user is followed by the user currently logged in.
"""
self._assert_auth()
with requests.no_error_handling():
resp = requests.get(
f"https://scratch.mit.edu/users/{self.username}/",
headers=self._headers,
cookies=self._cookies,
)
soup = BeautifulSoup(resp.text, "html.parser")
follow_btn = soup.select_one("div.follow-button")
if not follow_btn:
print("Warning: follow button not found in page.")
Copy link
Collaborator

@faretek1 faretek1 Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this may be better if it's done with warnings.warn but this should not happen anyway

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after some usage myself i realised that if you get your own user and try .is_followed_by_me() the follow button wouldn't be found in the page

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should this fall back to the less efficient functionality?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should this fall back to the less efficient functionality?

i think it's better if we just explicitly state in the docs how this function works and when to use it.

as i said in the PR body:

for users with small amount e.g. <20 followers, is_followed_by is actually faster, in my case (19 followers) 0.19s vs 0.94s.

but for those with more followers e.g. 100, is_followed_by is slower, in my case (131 followers) 1.58s vs 0.54s

i guess if you try iterate through like griffpatch's followers then is_followed_by would be a hell of a lot slower than is_followed_by_me.

so we should state that the is_followed_by_me method is best to use on users who 1) are NOT the currently logged in user and 2) have larger amount of followers.

of course i guess we could automate this by perhaps checking in is_followed_by if the username given is the one of the current session, and if the target user has over a set threshold of followers then switch to is_followed_by_me, but i guess that makes it unnecessarily complex and probably just easier to let the dev choose which one they need

Copy link
Contributor Author

@uukelele uukelele Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also one thing I noticed which I don't know why it wasn't implemented is that looking at the amount of times we fetch the users HTML profile page in User methods, maybe it'd be better to cache that?

or maybe we fetch the user page once when class created and store is_followed_by_me as a property? and then have .update() refresh this

return False # defualt to not followed
data_control = follow_btn.get("data-control")
return data_control == 'unfollow' # True if unfollow, False if not


def project_count(self):
with requests.no_error_handling():
text = requests.get(
Expand Down
7 changes: 6 additions & 1 deletion tests/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
def test_user():
if not credentials_available():
warnings.warn(
"Skipped test_studio because there were no credentials available."
"Skipped test_user because there were no credentials available."
)
return
sess = session()
Expand Down Expand Up @@ -106,6 +106,11 @@ def test_user():
assert status_data["status"] == "Sample status"
assert status_data["color"] == "#855cd6"

uukelele = sess.connect_user("uukelele") # could use anyone ScratchAttachV2 is following right now but i think its cool that its following my account - uukelele, 2026
assert uukelele.is_followed_by_me()
# and someone he is not following
assert not griffpatch.is_followed_by_me()


if __name__ == "__main__":
test_user()
Expand Down