abstract-github 0.0.0.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.
- abstract_github-0.0.0.1/LICENSE +46 -0
- abstract_github-0.0.0.1/PKG-INFO +18 -0
- abstract_github-0.0.0.1/README.md +1 -0
- abstract_github-0.0.0.1/setup.cfg +4 -0
- abstract_github-0.0.0.1/setup.py +27 -0
- abstract_github-0.0.0.1/src/abstract_github/__init__.py +4 -0
- abstract_github-0.0.0.1/src/abstract_github/call_manager.py +34 -0
- abstract_github-0.0.0.1/src/abstract_github/rate_limiter.py +69 -0
- abstract_github-0.0.0.1/src/abstract_github/safe_call_data.py +76 -0
- abstract_github-0.0.0.1/src/abstract_github/utils.py +10 -0
- abstract_github-0.0.0.1/src/abstract_github.egg-info/PKG-INFO +18 -0
- abstract_github-0.0.0.1/src/abstract_github.egg-info/SOURCES.txt +13 -0
- abstract_github-0.0.0.1/src/abstract_github.egg-info/dependency_links.txt +1 -0
- abstract_github-0.0.0.1/src/abstract_github.egg-info/requires.txt +1 -0
- abstract_github-0.0.0.1/src/abstract_github.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
This project is licensed under the MIT License
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
The MIT License was first developed at the Massachusetts Institute of Technology (MIT) in the late 1980s. The exact origins MIT license are bit of mystery. Like the Apache 2.0, and BSD family of licenses the MIT License is a permissive software license that places few restrictions of reuse. Users of software using an MIT License are permitted to use, copy, modify, merge publish, distribute, sublicense and sell copies of the software. Some notable projects use the MIT License including Ruby on Rails, and the X Windows System.
|
|
6
|
+
MIT License Conditions
|
|
7
|
+
The MIT License is relatively simple and short. Below is the text of the MIT License from the Open Software Initiative.
|
|
8
|
+
Begin license text.
|
|
9
|
+
|
|
10
|
+
Copyright <YEAR> <COPYRIGHT HOLDER>
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
17
|
+
End license text.
|
|
18
|
+
Using MIT Licensed Code
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
The basic conditions of using the MIT License are:
|
|
23
|
+
|
|
24
|
+
1. The original copyright notice
|
|
25
|
+
|
|
26
|
+
2. A copy of the license itself
|
|
27
|
+
|
|
28
|
+
are including in all copies or any substantial portions of the software.
|
|
29
|
+
MIT License Compatibility
|
|
30
|
+
|
|
31
|
+
The MIT License is highly compatible with other permissive licenses. Including the BSD family of licenses. It is generally compatible with GNU GPL group of licenses. However if you distribute the code that contains or is derivative of GNU GPL code the final project must of GPL compliant. In other words any source code must of publicly available.
|
|
32
|
+
MIT License, Patents
|
|
33
|
+
|
|
34
|
+
The MIT License was developed before patenting software was a common practice in the U.S. It therefore does not contain an express patent license. The broad nature of the license in general, is considered by some to encompass an implicit waiver of patent rights. If you are concerned about patent rights, the Apache 2.0 license contains an explicit contributor's patent license.
|
|
35
|
+
MIT No Attribution License (MIT-0)
|
|
36
|
+
|
|
37
|
+
The MIT No Attribution License is a Public Domain equivalent license it is similar to the BSD Free license.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
Copyright <YEAR><COPYRIGHT HOLDER>
|
|
42
|
+
|
|
43
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so.
|
|
44
|
+
|
|
45
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
46
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: abstract_github
|
|
3
|
+
Version: 0.0.0.1
|
|
4
|
+
Summary: abstract_github is a Python module that serves aggregates github data
|
|
5
|
+
Home-page: https://github.com/AbstractEndeavors/abstract_ai
|
|
6
|
+
Author: putkoff
|
|
7
|
+
Author-email: partners@abstractendeavors.com
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Requires-Python: >=3.6
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: abstract_utilities
|
|
17
|
+
|
|
18
|
+
#magnets who invented them; how do they work?
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#magnets who invented them; how do they work?
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from time import time
|
|
2
|
+
import setuptools
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
setuptools.setup(
|
|
6
|
+
name='abstract_github',
|
|
7
|
+
version='0.0.0.1',
|
|
8
|
+
author='putkoff',
|
|
9
|
+
author_email='partners@abstractendeavors.com',
|
|
10
|
+
description="abstract_github is a Python module that serves aggregates github data",
|
|
11
|
+
long_description=long_description,
|
|
12
|
+
long_description_content_type='text/markdown',
|
|
13
|
+
url='https://github.com/AbstractEndeavors/abstract_ai',
|
|
14
|
+
classifiers=[
|
|
15
|
+
'Development Status :: 3 - Alpha',
|
|
16
|
+
'Intended Audience :: Developers',
|
|
17
|
+
'License :: OSI Approved :: MIT License',
|
|
18
|
+
'Programming Language :: Python :: 3',
|
|
19
|
+
'Programming Language :: Python :: 3.11',
|
|
20
|
+
],
|
|
21
|
+
install_requires=['abstract_utilities'],
|
|
22
|
+
package_dir={"": "src"},
|
|
23
|
+
packages=setuptools.find_packages(where="src"),
|
|
24
|
+
python_requires=">=3.6",
|
|
25
|
+
# Add this line to include wheel format in your distribution
|
|
26
|
+
setup_requires=['wheel'],
|
|
27
|
+
)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from .safe_call_data import get_limited_call_safe,os,safe_dump_to_file,safe_read_from_json
|
|
2
|
+
from .utils import get_user_name_from_github_link
|
|
3
|
+
class completeCallsManager:
|
|
4
|
+
def __init__(self):
|
|
5
|
+
|
|
6
|
+
self.completed_list_path = os.path.join(os.getcwd(),'completed_list.json')
|
|
7
|
+
self.completed_list = self.load_completed_list()
|
|
8
|
+
def load_completed_list(self):
|
|
9
|
+
if not os.path.isfile(self.completed_list_path):
|
|
10
|
+
safe_dump_to_file(data={},file_path= self.completed_list_path)
|
|
11
|
+
self.completed_list = safe_read_from_json( self.completed_list_path)
|
|
12
|
+
return self.completed_list
|
|
13
|
+
async def call_data_check(self,username,data_type):
|
|
14
|
+
# Initialize user data if not already in completed_list
|
|
15
|
+
data={}
|
|
16
|
+
if self.completed_list.get(username) is None:
|
|
17
|
+
self.completed_list[username] = {"user_info": None, "repo_info": None}
|
|
18
|
+
# Check if data for this key exists in the completed_list_path
|
|
19
|
+
if self.completed_list.get(str(username), {}).get(str(data_type)) is None:
|
|
20
|
+
url = f"https://api.github.com/users/{username}"
|
|
21
|
+
|
|
22
|
+
# Modify the URL if we are fetching repo info
|
|
23
|
+
if data_type == 'repo_info':
|
|
24
|
+
url = f"{url}/repos"
|
|
25
|
+
|
|
26
|
+
# Fetch the data asynchronously (assuming this is an asynchronous function)
|
|
27
|
+
data = await get_limited_call_safe(url)
|
|
28
|
+
if data and isinstance(data,dict):
|
|
29
|
+
self.completed_list[username][data_type] = True
|
|
30
|
+
# Save the data in the completed_list
|
|
31
|
+
# Persist the updated completed_list to the JSON file
|
|
32
|
+
safe_dump_to_file(data=self.completed_list, file_path=self.completed_list_path)
|
|
33
|
+
|
|
34
|
+
return data
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import requests
|
|
3
|
+
from requests.exceptions import HTTPError
|
|
4
|
+
|
|
5
|
+
# GitHub API rate limits
|
|
6
|
+
RATE_LIMIT_URL = "https://api.github.com/rate_limit"
|
|
7
|
+
|
|
8
|
+
def rate_limited_api_call(url, method='GET', headers=None, data=None, max_retries=5):
|
|
9
|
+
"""
|
|
10
|
+
Make a rate-limited GitHub API call with retries and backoff on failure.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
- url (str): API endpoint URL.
|
|
14
|
+
- method (str): HTTP method ('GET', 'POST', 'PATCH', etc.).
|
|
15
|
+
- headers (dict): Optional HTTP headers.
|
|
16
|
+
- data (dict): Optional payload for POST/PATCH requests.
|
|
17
|
+
- max_retries (int): Maximum number of retries on failure.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
- Response object (requests.Response) if successful, None otherwise.
|
|
21
|
+
"""
|
|
22
|
+
retries = 0
|
|
23
|
+
while retries <= max_retries:
|
|
24
|
+
try:
|
|
25
|
+
# Make the API request
|
|
26
|
+
response = requests.request(method, url, headers=headers, json=data)
|
|
27
|
+
|
|
28
|
+
# Check for HTTP errors
|
|
29
|
+
response.raise_for_status()
|
|
30
|
+
|
|
31
|
+
# Check if we are rate-limited
|
|
32
|
+
remaining = int(response.headers.get('X-RateLimit-Remaining', 1))
|
|
33
|
+
reset_time = int(response.headers.get('X-RateLimit-Reset', time.time() + 60))
|
|
34
|
+
|
|
35
|
+
if remaining == 0:
|
|
36
|
+
# Calculate the wait time until the rate limit resets
|
|
37
|
+
sleep_time = max(0, reset_time - time.time())
|
|
38
|
+
print(f"Rate limit exceeded. Waiting for {sleep_time} seconds...")
|
|
39
|
+
time.sleep(sleep_time)
|
|
40
|
+
continue # Retry after waiting
|
|
41
|
+
|
|
42
|
+
return response # If request was successful
|
|
43
|
+
|
|
44
|
+
except HTTPError as http_err:
|
|
45
|
+
# Handle rate limit error (403 status)
|
|
46
|
+
if response.status_code == 403 and 'X-RateLimit-Remaining' in response.headers:
|
|
47
|
+
reset_time = int(response.headers['X-RateLimit-Reset'])
|
|
48
|
+
sleep_time = max(0, reset_time - time.time())
|
|
49
|
+
print(f"Rate limit hit, retrying in {sleep_time} seconds...")
|
|
50
|
+
time.sleep(sleep_time)
|
|
51
|
+
retries += 1
|
|
52
|
+
else:
|
|
53
|
+
print(f"HTTP error occurred: {http_err}")
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
except Exception as err:
|
|
57
|
+
print(f"Other error occurred: {err}")
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
# Exponential backoff for retries
|
|
61
|
+
retries += 1
|
|
62
|
+
backoff_time = 2 ** retries
|
|
63
|
+
print(f"Retrying in {backoff_time} seconds...")
|
|
64
|
+
time.sleep(backoff_time)
|
|
65
|
+
|
|
66
|
+
print("Max retries exceeded.")
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from .utils import *
|
|
2
|
+
from .rate_limiter import rate_limited_api_call
|
|
3
|
+
async def fetch_data_from_api(url):
|
|
4
|
+
"""
|
|
5
|
+
Simulate an async function that fetches data from an API.
|
|
6
|
+
Replace this with your actual API call logic.
|
|
7
|
+
"""
|
|
8
|
+
await asyncio.sleep(1) # Simulate network delay
|
|
9
|
+
return {"dummy_data": f"Data from {url}"}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def get_limited_call_safe(call_url,token=None):
|
|
13
|
+
"""
|
|
14
|
+
This function safely calls the API and logs both successful responses and errors.
|
|
15
|
+
"""
|
|
16
|
+
response_data = {}
|
|
17
|
+
|
|
18
|
+
print(call_url)
|
|
19
|
+
# Attempt to make the API call
|
|
20
|
+
user_info = rate_limited_api_call(call_url)
|
|
21
|
+
|
|
22
|
+
if user_info:
|
|
23
|
+
# Successful response, parse JSON
|
|
24
|
+
response_data = user_info
|
|
25
|
+
if response_data:
|
|
26
|
+
try:
|
|
27
|
+
response_data = response_data.json()
|
|
28
|
+
except:
|
|
29
|
+
response_data = response_data.text
|
|
30
|
+
response_data = process_templated_urls(response_data)
|
|
31
|
+
# Log the successful response
|
|
32
|
+
log_response(call_url, response_data)
|
|
33
|
+
try:
|
|
34
|
+
print('hihihi')
|
|
35
|
+
except Exception as e:
|
|
36
|
+
# If any error occurs, log it and add error details to the response
|
|
37
|
+
response_data = {
|
|
38
|
+
"response": None,
|
|
39
|
+
"error": True,
|
|
40
|
+
"error_message": str(e)
|
|
41
|
+
}
|
|
42
|
+
log_error(call_url, e)
|
|
43
|
+
|
|
44
|
+
return response_data
|
|
45
|
+
|
|
46
|
+
def process_templated_urls(obj):
|
|
47
|
+
"""
|
|
48
|
+
Recursively processes nested dictionaries and lists to replace template parts in URLs.
|
|
49
|
+
"""
|
|
50
|
+
if isinstance(obj, dict):
|
|
51
|
+
# Process dictionary by iterating through key-value pairs
|
|
52
|
+
for key, value in obj.items():
|
|
53
|
+
if isinstance(value, str):
|
|
54
|
+
# If a string contains a URL template, remove or replace it
|
|
55
|
+
if '{' in value:
|
|
56
|
+
obj[key] = value.replace('{/sha}', '').replace('{/other_user}', '').replace('{/gist_id}', '')
|
|
57
|
+
else:
|
|
58
|
+
# If value is a nested dictionary or list, process it recursively
|
|
59
|
+
obj[key] = process_templated_urls(value)
|
|
60
|
+
elif isinstance(obj, list):
|
|
61
|
+
# If the object is a list, process each element recursively
|
|
62
|
+
for i, item in enumerate(obj):
|
|
63
|
+
obj[i] = process_templated_urls(item)
|
|
64
|
+
|
|
65
|
+
return obj
|
|
66
|
+
def log_response(call_url, response):
|
|
67
|
+
"""
|
|
68
|
+
Logs the API response.
|
|
69
|
+
"""
|
|
70
|
+
logging.info(f"API Call to {call_url} succeeded. Response: {json.dumps(response)}")
|
|
71
|
+
|
|
72
|
+
def log_error(call_url, error):
|
|
73
|
+
"""
|
|
74
|
+
Logs any error that occurred during the API call.
|
|
75
|
+
"""
|
|
76
|
+
logging.error(f"API Call to {call_url} failed. Error: {str(error)}")
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import requests,asyncio,json,os
|
|
2
|
+
from abstract_utilities import *
|
|
3
|
+
base_url = "https://api.github.com/users/"
|
|
4
|
+
|
|
5
|
+
def get_github_from_user_name(username):
|
|
6
|
+
return f'https://github.com/{username}'
|
|
7
|
+
def get_user_name_from_github_link(github_link):
|
|
8
|
+
return make_list([subdir for subdir in github_link.split('github.com')[-1].split('/') if subdir] or None)[0]
|
|
9
|
+
def get_clean_string(string):
|
|
10
|
+
return eatAll(string,['/','\n',' ','\t']).split('/')[-1]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: abstract_github
|
|
3
|
+
Version: 0.0.0.1
|
|
4
|
+
Summary: abstract_github is a Python module that serves aggregates github data
|
|
5
|
+
Home-page: https://github.com/AbstractEndeavors/abstract_ai
|
|
6
|
+
Author: putkoff
|
|
7
|
+
Author-email: partners@abstractendeavors.com
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Requires-Python: >=3.6
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: abstract_utilities
|
|
17
|
+
|
|
18
|
+
#magnets who invented them; how do they work?
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
src/abstract_github/__init__.py
|
|
5
|
+
src/abstract_github/call_manager.py
|
|
6
|
+
src/abstract_github/rate_limiter.py
|
|
7
|
+
src/abstract_github/safe_call_data.py
|
|
8
|
+
src/abstract_github/utils.py
|
|
9
|
+
src/abstract_github.egg-info/PKG-INFO
|
|
10
|
+
src/abstract_github.egg-info/SOURCES.txt
|
|
11
|
+
src/abstract_github.egg-info/dependency_links.txt
|
|
12
|
+
src/abstract_github.egg-info/requires.txt
|
|
13
|
+
src/abstract_github.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
abstract_utilities
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
abstract_github
|