# hubcap
A [dol](https://github.com/i2mint/dol) (i.e. dict-like) interface to github
To install: ```pip install hubcap```
# Examples
## Basics
The simplest facade to github data.
Interact with github like you'd interact with a `dict` object.
Warning: You'll need to have a github api token (google it if you don't have one;
it's easy to get). You'll have to specify this token when making hubcap objects,
or put it in an environmental variable under the name `GITHUB_TOKEN` or `HUBCAP_GITHUB_TOKEN`
(useful since github actions doesn't allow you to have env variables starting with `GITHUB`).
```python
>>> s = GitHubReader('thorwhalen') # connnecting to a particular user/organization
>>> list(s) # doctest: +SKIP
['agen',
'aix',
...
'viral',
'wealth',
'wrapt']
>>> 'a_non_existing_repository_name' in s
False
>>> 'hubcap' in s # of course, this will be true, it's what you're using now!
True
>>> repo = s['hubcap']
>>> list(repo)
['master']
>>> branch = repo['master']
>>> list(branch) # doctest: +NORMALIZE_WHITESPACE
['/.gitattributes',
'/.github/',
'/.gitignore',
'/LICENSE',
'/README.md',
'/docsrc/',
'/hubcap/',
'/setup.cfg',
'/setup.py']
>>> content = branch['/setup.cfg']
>>> print(content[:32].decode())
[metadata]
name = hubcap
version
```
## Listing repositories and information about them
List repositories for a given user or organization, along with 78 fields of info.
```python
>>> from hubcap.examples import repos_info, actions_info
>>>
>>> repos = repos_info('i2mint') # doctest: +SKIP
>>> print(repos.shape) # doctest: +SKIP
(60, 78)
>>> repos.head() # doctest: +SKIP
id node_id name ... watchers default_branch permissions
full_name ...
i2mint/py2mqtt 425694616 R_kgDOGV-VmA py2mqtt ... 0 main {'admin': True, 'maintain': True, 'push': True...
i2mint/mongodol 341721959 MDEwOlJlcG9zaXRvcnkzNDE3MjE5NTk= mongodol ... 0 master {'admin': True, 'maintain': True, 'push': True...
i2mint/dol 299438731 MDEwOlJlcG9zaXRvcnkyOTk0Mzg3MzE= dol ... 4 master {'admin': True, 'maintain': True, 'push': True...
i2mint/stream2py 238989487 MDEwOlJlcG9zaXRvcnkyMzg5ODk0ODc= stream2py ... 2 master {'admin': True, 'maintain': True, 'push': True...
i2mint/creek 321448350 MDEwOlJlcG9zaXRvcnkzMjE0NDgzNTA= creek ... 0 master {'admin': True, 'maintain': True, 'push': True...
[5 rows x 78 columns]
>>> list(repos.columns) # doctest: +SKIP
['id', 'node_id', 'name', 'full_name', 'private', 'owner', 'html_url', 'description',
'fork', 'url', 'forks_url', 'keys_url', 'collaborators_url', 'teams_url', 'hooks_url
', 'issue_events_url', 'events_url', 'assignees_url', 'branches_url', 'tags_url',
'blobs_url', 'git_tags_url', 'git_refs_url', 'trees_url', 'statuses_url', 'languages_url
', 'stargazers_url', 'contributors_url', 'subscribers_url', 'subscription_url',
'commits_url', 'git_commits_url', 'comments_url', 'issue_comment_url', 'contents_url',
'compare_url', 'merges_url', 'archive_url', 'downloads_url', 'issues_url', 'pulls_url',
'milestones_url', 'notifications_url', 'labels_url', 'releases_url', 'deployments_url
', 'created_at', 'updated_at', 'pushed_at', 'git_url', 'ssh_url', 'clone_url', 'svn_url',
'homepage', 'size', 'stargazers_count', 'watchers_count', 'language', 'has_issue
s', 'has_projects', 'has_downloads', 'has_wiki', 'has_pages', 'forks_count',
'mirror_url', 'archived', 'disabled', 'open_issues_count', 'license', 'allow_forking',
'is_template', 'topics', 'visibility', 'forks', 'open_issues', 'watchers',
'default_branch', 'permissions']
```
Get info about github actions for a given repository.
```python
>>> actions = actions_info('i2mint/mongodol') # doctest: +SKIP
>>> print(actions.shape) # doctest: +SKIP
(10, 30)
>>> actions.head() # doctest: +SKIP
id name ... repository head_repository
0 1468986198 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...
1 1445456774 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...
2 1437461380 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...
3 1343133456 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...
4 1262878182 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...
[5 rows x 30 columns]
>>>
>>> list(actions.columns) # doctest: +SKIP
['id', 'name', 'node_id', 'head_branch', 'head_sha', 'run_number', 'event', 'status',
'conclusion', 'workflow_id', 'check_suite_id', 'check_suite_node_id', 'url', 'html_url',
'pull_requests', 'created_at', 'updated_at', 'run_attempt', 'run_started_at',
'jobs_url', 'logs_url', 'check_suite_url', 'artifacts_url', 'cancel_url', 'rerun_url',
'previous_attempt_url', 'workflow_url', 'head_commit', 'repository', 'head_repository']
```
Find most recently changed repositories and check if their CI failed or not.
```python
>>> from hubcap.examples import date_selection_lidx
>>> updated_recently = repos.iloc
... [date_selection_lidx(repos, hours_ago=24)] # doctest: +SKIP
>>> {repo: get_last_build_status(repo)
... for repo in updated_recently['full_name']} # doctest: +SKIP
{'i2mint/py2mqtt': 'failure',
'i2mint/mongodol': 'success',
'i2mint/dol': 'success',
'i2mint/stream2py': 'success',
'i2mint/creek': 'success'}
```
Note: You can get this directly using the `ci_status` function
```python
>>> from hubcap.examples import ci_status
>>> ci_status('i2mint', hours_ago=24) # doctest: +SKIP
{'i2mint/py2mqtt': 'failure',
'i2mint/mongodol': 'success',
'i2mint/dol': 'success',
'i2mint/stream2py': 'success',
'i2mint/creek': 'success'}
```
## RepoReader
```python
>>> from hubcap import RepoReader
>>> r = RepoReader('thorwhalen/test_repo')
>>> sorted(r) # doctest: +SKIP
['artifacts', 'assignees', 'autolinks', 'branches', 'codescan_alerts', 'collaborators',
'comments', 'commits', 'contributors', 'deployments', 'discussions', 'downloads',
'environments', 'events', 'forks', 'git_refs', 'hooks', 'issues', 'issues_comments',
'issues_events', 'labels', 'languages', 'milestones', 'network_events',
'notifications', 'pending_invitations', 'projects', 'pulls', 'pulls_comments',
'pulls_review_comments', 'releases', 'repository_advisories', 'secrets',
'self_hosted_runners', 'stargazers', 'stargazers_with_dates', 'stats_contributors',
'subscribers', 'tags', 'teams', 'top_paths', 'top_referrers', 'topics', 'variables',
'watchers', 'workflow_runs', 'workflows']
>>>
>>> 'issues' in r
True
>>> issues = r['issues']
>>> sorted(issues)
[4, 5]
>>> issue_obj = issues[4]
>>> issue_obj
Issue(title="Test Issue A", number=4)
>>> sorted([attr for attr in dir(issue_obj) if not attr.startswith('_')]) # doctest: +SKIP
['CHECK_AFTER_INIT_FLAG', 'active_lock_reason', 'add_to_assignees', 'add_to_labels',
'as_pull_request', 'assignee', 'assignees', 'body', 'closed_at', 'closed_by',
'comments', 'comments_url', 'create_comment', 'create_reaction', 'created_at',
'delete_labels', 'delete_reaction', 'edit', 'etag', 'events_url', 'get__repr__',
'get_comment', 'get_comments', 'get_events', 'get_labels', 'get_reactions',
'get_timeline', 'html_url', 'id', 'labels', 'labels_url', 'last_modified', 'lock',
'locked', 'milestone', 'number', 'pull_request', 'raw_data', 'raw_headers',
'remove_from_assignees', 'remove_from_labels', 'repository', 'setCheckAfterInitFlag',
'set_labels', 'state', 'state_reason', 'title', 'unlock', 'update', 'updated_at',
'url', 'user']
>>> issue_obj.number
4
>>> issue_obj.state
'open'
>>> issue_obj.labels
[Label(name="documentation"), Label(name="enhancement")]
>>> # title of issue
>>> issue_obj.title
'Test Issue A'
>>> # content of issue
>>> issue_obj.body
'Contents of Test Issue A'
>>>
>>> issue_obj.comments
2
>>>
>>> list(issue_obj.get_comments()) # doctest: +NORMALIZE_WHITESPACE
[IssueComment(user=NamedUser(login="thorwhalen"), id=1801792378),
IssueComment(user=NamedUser(login="thorwhalen"), id=1801792855)]
>>> issue_comment = issue_obj.get_comment(1801792378)
>>> issue_comment.body
'Comment 1 of Test Issue A'
>>>
>>> 'discussions' in r
True
>>> discussions = r['discussions'] # doctest: +SKIP
>>> sorted(discussions) # doctest: +SKIP
[1, 2, 3]
```
## hub function
The high level function `hub` is the simplest way to get started. It's a
function that takes a path to a github resource and returns a mapping to that
resource. The mapping is lazy, so it's only when you access a key that the
resource is actually fetched from github.
```python
>>> repositories = hub('thorwhalen')
>>> 'hubcap' in repositories
True
>>> hubcap_repo = repositories['hubcap']
>>>
>>> repo = hub('thorwhalen/hubcap')
>>> 'master' in repo
True
>>> master_files = repo['master']
>>>
>>> files = hub('thorwhalen/hubcap/master')
>>> '/README.md' in files
True
>>> '/hubcap/' in files
True
>>> hubcap_files = files['/hubcap/']
>>> '/hubcap/base.py' in hubcap_files
True
```
### Access issues
```python
>>> issues = hub('thorwhalen/hubcap/issues')
>>> 3 in issues # there's a "number 3" issue
True
>>> issue = issues[3]
>>> issue.title
'Test Issue'
>>> issue.body
'This is just a test issue to test that hubcap can see it.\r\n'
>>> issue.comments # meaning "number of comments"
1
```
### Access discussions
```python
>>> discussions = hub('thorwhalen/hubcap/discussions') # doctest: +SKIP
>>> # get a list of discussion (keys)
>>> list(discussions) # doctest: +SKIP
[2, ...]
>>> # the discussion 2 should be included in that list
>>> 2 in discussions # doctest: +SKIP
True
>>> discussion = discussions[2] # doctest: +SKIP
>>> discussion # doctest: +SKIP
{'number': 2,
'title': 'Root interface of hubcap',
'body': 'Every time I need to do something with `hubcap` ...',
'author': {'login': 'thorwhalen'},
'createdAt': '2023-11-07T09:30:59Z',
'updatedAt': '2023-12-05T08:25:39Z',
'comments': [{'body': 'Further it would be nice if we ...',
'author': 'thorwhalen',
'replies': []}]}
>>> discussion['title'] # doctest: +SKIP
'Root interface of hubcap'
```
Here's a nice trick for those want to download a discussion in a nice readable format,
for you, or some AI, to look through.
```python
>>> from hubcap import create_markdown_from_jdict
>>> markdown_string = create_markdown_from_jdict(discussion) # doctest: +SKIP
>>> print(markdown_string) # doctest: +SKIP
# Root interface of hubcap
<BLANKLINE>
Every time I need to do something with `hubcap` I need to look up how it works again.
<BLANKLINE>
That's negative points
```
## GithubReader
One of the main classes is `GithubReader`. It's a mapping that connects to a
github user or organization, and returns a mapping of repositories. The
repositories are also mappings, that return mappings of branches, and so on.
```python
>>> from hubcap import GithubReader
>>> s = GithubReader('thorwhalen') # connnecting to a particular user/organization
>>> list(s) # doctest: +SKIP
['agen',
'aix',
...
'viral',
'wealth',
'wrapt']
>>> 'a_non_existing_repository_name' in s
False
>>> 'hubcap' in s # of course, this will be true, it's what you're using now!
True
>>> repo = s['hubcap']
>>> list(repo)
['master']
>>> branch = repo['master']
>>> list(branch) # doctest: +NORMALIZE_WHITESPACE
['/.gitattributes', '/.github/', '/.gitignore', '/LICENSE',
'/README.md', '/docsrc/', '/hubcap/', '/misc/', '/setup.cfg', '/setup.py']
>>> content = branch['/setup.cfg']
>>> print(content[:32].decode())
[metadata]
name = hubcap
version
>>> from hubcap import get_repository_info
>>> info = get_repository_info('thorwhalen/hubcap')
>>> list(info) # doctest: +NORMALIZE_WHITESPACE
['name', 'full_name', 'description', 'stargazers_count',
'forks_count', 'watchers_count', 'html_url', 'last_commit_date']
>>> info['name']
'hubcap'
>>> info['html_url']
'https://github.com/thorwhalen/hubcap'
>>> info['stargazers_count'] >= 1
True
```
You also have other useful objects, like `Issues`, `IssueComments`, `Discussions`, etc.
## github_repo_text_aggregate
```python
>>> owner_repo_files = github_repo_text_aggregate('thorwhalen/hubcap') # doctest: +SKIP
>>> markdown_output = github_repo_text_aggregate(owner_repo_files) # doctest: +SKIP
```
# Recipes
## Clone to temp folder and get store (mapping) of files
```python
from hubcap import git_clone, git_wiki_clone
from dol import TextFiles, filt_iter, Pipe
repo_py_files = Pipe(
git_clone, TextFiles, filt_iter(filt=lambda x: x.endswith('.py'))
)
repo_wiki_files = Pipe(git_wiki_clone, TextFiles)
```
```python
py_files = repo_py_files('i2mint/dol')
len(py_files)
# 37
```
```python
wiki_files = repo_wiki_files('i2mint/dol')
list(wiki_files)
# ['Recipes.md',
# 'Critiques-and-their-comebacks.md',
# 'Home.md',
# 'Mapping-Views.md']
```
Raw data
{
"_id": null,
"home_page": "https://github.com/thorwhalen/hubcap",
"name": "hubcap",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "github",
"author": "Thor Whalen",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/ad/5e/72f1528f8c5d0cab07385f2d98810115cd3594ca43e8a0c40cd25c201ccf/hubcap-0.1.9.tar.gz",
"platform": "any",
"description": "# hubcap\nA [dol](https://github.com/i2mint/dol) (i.e. dict-like) interface to github\n\nTo install:\t```pip install hubcap```\n\n\n# Examples\n\n## Basics\n\nThe simplest facade to github data.\n\nInteract with github like you'd interact with a `dict` object.\n\nWarning: You'll need to have a github api token (google it if you don't have one;\nit's easy to get). You'll have to specify this token when making hubcap objects,\nor put it in an environmental variable under the name `GITHUB_TOKEN` or `HUBCAP_GITHUB_TOKEN` \n(useful since github actions doesn't allow you to have env variables starting with `GITHUB`).\n\n\n```python\n>>> s = GitHubReader('thorwhalen') # connnecting to a particular user/organization\n>>> list(s) # doctest: +SKIP\n['agen',\n 'aix',\n ...\n 'viral',\n 'wealth',\n 'wrapt']\n>>> 'a_non_existing_repository_name' in s\nFalse\n>>> 'hubcap' in s # of course, this will be true, it's what you're using now!\nTrue\n>>> repo = s['hubcap']\n>>> list(repo)\n['master']\n>>> branch = repo['master']\n>>> list(branch) # doctest: +NORMALIZE_WHITESPACE\n['/.gitattributes',\n '/.github/',\n '/.gitignore',\n '/LICENSE',\n '/README.md',\n '/docsrc/',\n '/hubcap/',\n '/setup.cfg',\n '/setup.py']\n>>> content = branch['/setup.cfg']\n>>> print(content[:32].decode())\n[metadata]\nname = hubcap\nversion\n```\n\n\n## Listing repositories and information about them\n\n\nList repositories for a given user or organization, along with 78 fields of info.\n\n```python\n>>> from hubcap.examples import repos_info, actions_info\n>>>\n>>> repos = repos_info('i2mint') # doctest: +SKIP\n>>> print(repos.shape) # doctest: +SKIP\n(60, 78)\n>>> repos.head() # doctest: +SKIP\n id node_id name ... watchers default_branch permissions\nfull_name ...\ni2mint/py2mqtt 425694616 R_kgDOGV-VmA py2mqtt ... 0 main {'admin': True, 'maintain': True, 'push': True...\ni2mint/mongodol 341721959 MDEwOlJlcG9zaXRvcnkzNDE3MjE5NTk= mongodol ... 0 master {'admin': True, 'maintain': True, 'push': True...\ni2mint/dol 299438731 MDEwOlJlcG9zaXRvcnkyOTk0Mzg3MzE= dol ... 4 master {'admin': True, 'maintain': True, 'push': True...\ni2mint/stream2py 238989487 MDEwOlJlcG9zaXRvcnkyMzg5ODk0ODc= stream2py ... 2 master {'admin': True, 'maintain': True, 'push': True...\ni2mint/creek 321448350 MDEwOlJlcG9zaXRvcnkzMjE0NDgzNTA= creek ... 0 master {'admin': True, 'maintain': True, 'push': True...\n\n[5 rows x 78 columns]\n>>> list(repos.columns) # doctest: +SKIP\n['id', 'node_id', 'name', 'full_name', 'private', 'owner', 'html_url', 'description',\n'fork', 'url', 'forks_url', 'keys_url', 'collaborators_url', 'teams_url', 'hooks_url\n', 'issue_events_url', 'events_url', 'assignees_url', 'branches_url', 'tags_url',\n'blobs_url', 'git_tags_url', 'git_refs_url', 'trees_url', 'statuses_url', 'languages_url\n', 'stargazers_url', 'contributors_url', 'subscribers_url', 'subscription_url',\n'commits_url', 'git_commits_url', 'comments_url', 'issue_comment_url', 'contents_url',\n'compare_url', 'merges_url', 'archive_url', 'downloads_url', 'issues_url', 'pulls_url',\n'milestones_url', 'notifications_url', 'labels_url', 'releases_url', 'deployments_url\n', 'created_at', 'updated_at', 'pushed_at', 'git_url', 'ssh_url', 'clone_url', 'svn_url',\n'homepage', 'size', 'stargazers_count', 'watchers_count', 'language', 'has_issue\ns', 'has_projects', 'has_downloads', 'has_wiki', 'has_pages', 'forks_count',\n'mirror_url', 'archived', 'disabled', 'open_issues_count', 'license', 'allow_forking',\n'is_template', 'topics', 'visibility', 'forks', 'open_issues', 'watchers',\n'default_branch', 'permissions']\n\n```\n\n\nGet info about github actions for a given repository.\n\n```python\n>>> actions = actions_info('i2mint/mongodol') # doctest: +SKIP\n>>> print(actions.shape) # doctest: +SKIP\n(10, 30)\n>>> actions.head() # doctest: +SKIP\n id name ... repository head_repository\n0 1468986198 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...\n1 1445456774 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...\n2 1437461380 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...\n3 1343133456 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...\n4 1262878182 Continuous Integration ... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv... {'id': 341721959, 'node_id': 'MDEwOlJlcG9zaXRv...\n\n[5 rows x 30 columns]\n>>>\n>>> list(actions.columns) # doctest: +SKIP\n['id', 'name', 'node_id', 'head_branch', 'head_sha', 'run_number', 'event', 'status',\n'conclusion', 'workflow_id', 'check_suite_id', 'check_suite_node_id', 'url', 'html_url',\n'pull_requests', 'created_at', 'updated_at', 'run_attempt', 'run_started_at',\n'jobs_url', 'logs_url', 'check_suite_url', 'artifacts_url', 'cancel_url', 'rerun_url',\n'previous_attempt_url', 'workflow_url', 'head_commit', 'repository', 'head_repository']\n```\n\n\nFind most recently changed repositories and check if their CI failed or not.\n\n```python\n>>> from hubcap.examples import date_selection_lidx\n>>> updated_recently = repos.iloc\n... [date_selection_lidx(repos, hours_ago=24)] # doctest: +SKIP\n>>> {repo: get_last_build_status(repo)\n... for repo in updated_recently['full_name']} # doctest: +SKIP\n{'i2mint/py2mqtt': 'failure',\n 'i2mint/mongodol': 'success',\n 'i2mint/dol': 'success',\n 'i2mint/stream2py': 'success',\n 'i2mint/creek': 'success'}\n```\n\n\nNote: You can get this directly using the `ci_status` function\n\n```python\n>>> from hubcap.examples import ci_status\n>>> ci_status('i2mint', hours_ago=24) # doctest: +SKIP\n{'i2mint/py2mqtt': 'failure',\n 'i2mint/mongodol': 'success',\n 'i2mint/dol': 'success',\n 'i2mint/stream2py': 'success',\n 'i2mint/creek': 'success'}\n```\n\n\n## RepoReader\n\n```python\n>>> from hubcap import RepoReader\n>>> r = RepoReader('thorwhalen/test_repo')\n>>> sorted(r) # doctest: +SKIP\n['artifacts', 'assignees', 'autolinks', 'branches', 'codescan_alerts', 'collaborators', \n'comments', 'commits', 'contributors', 'deployments', 'discussions', 'downloads', \n'environments', 'events', 'forks', 'git_refs', 'hooks', 'issues', 'issues_comments', \n'issues_events', 'labels', 'languages', 'milestones', 'network_events', \n'notifications', 'pending_invitations', 'projects', 'pulls', 'pulls_comments', \n'pulls_review_comments', 'releases', 'repository_advisories', 'secrets', \n'self_hosted_runners', 'stargazers', 'stargazers_with_dates', 'stats_contributors', \n'subscribers', 'tags', 'teams', 'top_paths', 'top_referrers', 'topics', 'variables', \n'watchers', 'workflow_runs', 'workflows']\n>>>\n>>> 'issues' in r\nTrue\n>>> issues = r['issues']\n>>> sorted(issues)\n[4, 5]\n>>> issue_obj = issues[4]\n>>> issue_obj\nIssue(title=\"Test Issue A\", number=4)\n>>> sorted([attr for attr in dir(issue_obj) if not attr.startswith('_')]) # doctest: +SKIP\n['CHECK_AFTER_INIT_FLAG', 'active_lock_reason', 'add_to_assignees', 'add_to_labels', \n'as_pull_request', 'assignee', 'assignees', 'body', 'closed_at', 'closed_by', \n'comments', 'comments_url', 'create_comment', 'create_reaction', 'created_at', \n'delete_labels', 'delete_reaction', 'edit', 'etag', 'events_url', 'get__repr__', \n'get_comment', 'get_comments', 'get_events', 'get_labels', 'get_reactions', \n'get_timeline', 'html_url', 'id', 'labels', 'labels_url', 'last_modified', 'lock', \n'locked', 'milestone', 'number', 'pull_request', 'raw_data', 'raw_headers', \n'remove_from_assignees', 'remove_from_labels', 'repository', 'setCheckAfterInitFlag', \n'set_labels', 'state', 'state_reason', 'title', 'unlock', 'update', 'updated_at', \n'url', 'user']\n>>> issue_obj.number\n4\n>>> issue_obj.state\n'open'\n>>> issue_obj.labels\n[Label(name=\"documentation\"), Label(name=\"enhancement\")]\n>>> # title of issue\n>>> issue_obj.title\n'Test Issue A'\n>>> # content of issue\n>>> issue_obj.body\n'Contents of Test Issue A'\n>>>\n>>> issue_obj.comments\n2\n>>>\n>>> list(issue_obj.get_comments()) # doctest: +NORMALIZE_WHITESPACE\n[IssueComment(user=NamedUser(login=\"thorwhalen\"), id=1801792378), \nIssueComment(user=NamedUser(login=\"thorwhalen\"), id=1801792855)]\n>>> issue_comment = issue_obj.get_comment(1801792378)\n>>> issue_comment.body\n'Comment 1 of Test Issue A'\n>>>\n>>> 'discussions' in r\nTrue\n>>> discussions = r['discussions'] # doctest: +SKIP\n>>> sorted(discussions) # doctest: +SKIP\n[1, 2, 3]\n```\n\n\n## hub function\n\nThe high level function `hub` is the simplest way to get started. It's a\nfunction that takes a path to a github resource and returns a mapping to that\nresource. The mapping is lazy, so it's only when you access a key that the\nresource is actually fetched from github.\n\n```python\n>>> repositories = hub('thorwhalen')\n>>> 'hubcap' in repositories\nTrue\n>>> hubcap_repo = repositories['hubcap']\n>>>\n>>> repo = hub('thorwhalen/hubcap')\n>>> 'master' in repo\nTrue\n>>> master_files = repo['master']\n>>>\n>>> files = hub('thorwhalen/hubcap/master')\n>>> '/README.md' in files\nTrue\n>>> '/hubcap/' in files\nTrue\n>>> hubcap_files = files['/hubcap/']\n>>> '/hubcap/base.py' in hubcap_files\nTrue\n```\n\n### Access issues\n\n```python\n>>> issues = hub('thorwhalen/hubcap/issues')\n>>> 3 in issues # there's a \"number 3\" issue\nTrue\n>>> issue = issues[3]\n>>> issue.title\n'Test Issue'\n>>> issue.body\n'This is just a test issue to test that hubcap can see it.\\r\\n'\n>>> issue.comments # meaning \"number of comments\"\n1\n```\n\n### Access discussions\n\n```python\n>>> discussions = hub('thorwhalen/hubcap/discussions') # doctest: +SKIP\n>>> # get a list of discussion (keys)\n>>> list(discussions) # doctest: +SKIP\n[2, ...]\n>>> # the discussion 2 should be included in that list\n>>> 2 in discussions # doctest: +SKIP\nTrue\n>>> discussion = discussions[2] # doctest: +SKIP\n>>> discussion # doctest: +SKIP\n{'number': 2,\n 'title': 'Root interface of hubcap',\n 'body': 'Every time I need to do something with `hubcap` ...',\n 'author': {'login': 'thorwhalen'},\n 'createdAt': '2023-11-07T09:30:59Z',\n 'updatedAt': '2023-12-05T08:25:39Z',\n 'comments': [{'body': 'Further it would be nice if we ...',\n 'author': 'thorwhalen',\n 'replies': []}]}\n>>> discussion['title'] # doctest: +SKIP\n'Root interface of hubcap'\n```\n\nHere's a nice trick for those want to download a discussion in a nice readable format, \nfor you, or some AI, to look through. \n\n```python \n>>> from hubcap import create_markdown_from_jdict\n>>> markdown_string = create_markdown_from_jdict(discussion) # doctest: +SKIP\n>>> print(markdown_string) # doctest: +SKIP\n# Root interface of hubcap\n<BLANKLINE>\nEvery time I need to do something with `hubcap` I need to look up how it works again. \n<BLANKLINE>\nThat's negative points\n```\n\n## GithubReader\n\nOne of the main classes is `GithubReader`. It's a mapping that connects to a\ngithub user or organization, and returns a mapping of repositories. The\nrepositories are also mappings, that return mappings of branches, and so on.\n\n```python\n>>> from hubcap import GithubReader\n>>> s = GithubReader('thorwhalen') # connnecting to a particular user/organization\n>>> list(s) # doctest: +SKIP\n['agen',\n 'aix',\n ...\n 'viral',\n 'wealth',\n 'wrapt']\n>>> 'a_non_existing_repository_name' in s\nFalse\n>>> 'hubcap' in s # of course, this will be true, it's what you're using now!\nTrue\n>>> repo = s['hubcap']\n>>> list(repo)\n['master']\n>>> branch = repo['master']\n>>> list(branch) # doctest: +NORMALIZE_WHITESPACE\n['/.gitattributes', '/.github/', '/.gitignore', '/LICENSE',\n'/README.md', '/docsrc/', '/hubcap/', '/misc/', '/setup.cfg', '/setup.py']\n>>> content = branch['/setup.cfg']\n>>> print(content[:32].decode())\n[metadata]\nname = hubcap\nversion\n\n>>> from hubcap import get_repository_info\n>>> info = get_repository_info('thorwhalen/hubcap')\n>>> list(info) # doctest: +NORMALIZE_WHITESPACE\n['name', 'full_name', 'description', 'stargazers_count',\n'forks_count', 'watchers_count', 'html_url', 'last_commit_date']\n>>> info['name']\n'hubcap'\n>>> info['html_url']\n'https://github.com/thorwhalen/hubcap'\n>>> info['stargazers_count'] >= 1\nTrue\n```\n\nYou also have other useful objects, like `Issues`, `IssueComments`, `Discussions`, etc. \n\n\n## github_repo_text_aggregate\n\n```python\n>>> owner_repo_files = github_repo_text_aggregate('thorwhalen/hubcap') # doctest: +SKIP\n>>> markdown_output = github_repo_text_aggregate(owner_repo_files) # doctest: +SKIP\n```\n\n\n# Recipes\n\n## Clone to temp folder and get store (mapping) of files\n\n```python\nfrom hubcap import git_clone, git_wiki_clone\nfrom dol import TextFiles, filt_iter, Pipe\n\nrepo_py_files = Pipe(\n git_clone, TextFiles, filt_iter(filt=lambda x: x.endswith('.py'))\n)\nrepo_wiki_files = Pipe(git_wiki_clone, TextFiles)\n```\n\n```python\npy_files = repo_py_files('i2mint/dol')\nlen(py_files)\n# 37\n```\n\n```python\nwiki_files = repo_wiki_files('i2mint/dol')\nlist(wiki_files)\n# ['Recipes.md',\n# 'Critiques-and-their-comebacks.md',\n# 'Home.md',\n# 'Mapping-Views.md']\n```\n",
"bugtrack_url": null,
"license": "apache-2.0",
"summary": "A py2store (i.e. dict-like) interface to github",
"version": "0.1.9",
"project_urls": {
"Homepage": "https://github.com/thorwhalen/hubcap"
},
"split_keywords": [
"github"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "ad5e72f1528f8c5d0cab07385f2d98810115cd3594ca43e8a0c40cd25c201ccf",
"md5": "b8522aa3fe52a2bb34e28e95c2cd68ae",
"sha256": "0c70d3b375e84ebbed80910b7110eb8e6ce834809913fa82d64dde38b0cd3a25"
},
"downloads": -1,
"filename": "hubcap-0.1.9.tar.gz",
"has_sig": false,
"md5_digest": "b8522aa3fe52a2bb34e28e95c2cd68ae",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 40894,
"upload_time": "2024-11-29T16:04:25",
"upload_time_iso_8601": "2024-11-29T16:04:25.176343Z",
"url": "https://files.pythonhosted.org/packages/ad/5e/72f1528f8c5d0cab07385f2d98810115cd3594ca43e8a0c40cd25c201ccf/hubcap-0.1.9.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-29 16:04:25",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "thorwhalen",
"github_project": "hubcap",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "hubcap"
}