Skip to content

immutable IncompleteRequest.__getattr__ #74

Open
@mattsb42

Description

@mattsb42

I've been using this client in one of my projects[1] and I'm loving that I don't need to do anything to incorporate new API additions but I've run into a lot of issues trying to reuse partial constructions because IncompleteRequest.__getattr__ modifies self rather than returning a new request.

For example, if I want to get the branch protection details for every branch in a repo, I would assume that I could just do something along the lines of the below (actual url mutation in comments):

import os
import sys

from agithub.GitHub import GitHub

def all_branch_protection_data(username, repo_name):
    client = GitHub(token=os.environ["GITHUB_TOKEN"], paginate=True)

    repo = getattr(getattr(client.repos, username), repo_name)
    # repo.url == /repos/:owner/:repo
    print(repo.url)

    status, data = repo.branches.get()
    # repo.url == /repos/:owner/:repo/branches
    print(repo.url)

    # BASELINE == /repos/:owner/:repo/branches
    # LOOP_BASELINE = BASELINE
    for branch in data:
        branch = getattr(repo.branches, branch["name"])
        # branch is repo; repo.url == LOOP_BASELINE/branches/:branch
        print(repo.url)
        status, data = branch.protection.get()
        # branch is repo; repo.url == LOOP_BASELINE/branches/:branch/protection
        print(repo.url)
        yield data
        # LOOP_BASELINE = LOOP_BASELINE/branches/:branch/protection

if __name__ == "__main__":
    list(all_branch_protection_data(sys.argv[1], sys.argv[2]))

However, if I were to try this, it would not do what I would think it should, because every call to __getattr__ mutates repo.url.

/repos/mattsb42/rhodes
/repos/mattsb42/rhodes/branches
/repos/mattsb42/rhodes/branches/branches/development
/repos/mattsb42/rhodes/branches/branches/development/protection
/repos/mattsb42/rhodes/branches/branches/development/protection/branches/master
/repos/mattsb42/rhodes/branches/branches/development/protection/branches/master/protection
/repos/mattsb42/rhodes/branches/branches/development/protection/branches/master/protection/branches/wat
/repos/mattsb42/rhodes/branches/branches/development/protection/branches/master/protection/branches/wat/protection

I can work around this by resetting repo.url at the start of every iteration of the loop, but this seems to me like a common enough general use-case that I suspect that a large percentage of users are also running into this.

The fix for this is fairly simple, but would be a potentially significant breaking change to the client behavior. I'll go ahead and send up a PR for this because the change is so small, but I'm also happy to discuss the problem more here if you like.

[1] https://github.com/mattsb42/repo-manager

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions