diff --git a/.gitignore b/.gitignore index 97239f9..0c6e349 100644 --- a/.gitignore +++ b/.gitignore @@ -140,10 +140,6 @@ cython_debug/ # ---> VisualStudioCode .vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json *.code-workspace # Local History for Visual Studio Code @@ -232,7 +228,8 @@ fabric.properties .LSOverride # Icon must end with two \r -Icon +Icon + # Thumbnails ._* diff --git a/Pipfile b/Pipfile index 37fc8d4..cacdb12 100644 --- a/Pipfile +++ b/Pipfile @@ -7,7 +7,8 @@ name = "pypi" tweepy = "==4.10.1" [dev-packages] -autopep8 = "==1.7.0" +autopep8 = "*" +bandit = "*" [requires] python_version = "3.10" diff --git a/Pipfile.lock b/Pipfile.lock index f86254e..cae1a37 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a94545d640dcc28fce0a26b5d40dfaebf886910d87df38ab7bbe4ab7ec69f066" + "sha256": "3dc4c0a387fc9c5280d0dbfadae8f3d7cac3ddf589af5ec78dfe7090ff2684f2" }, "pipfile-spec": 6, "requires": { @@ -21,7 +21,7 @@ "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==2022.6.15" }, "charset-normalizer": { @@ -29,7 +29,7 @@ "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==2.1.1" }, "idna": { @@ -45,7 +45,7 @@ "sha256:23a8208d75b902797ea29fd31fa80a15ed9dc2c6c16fe73f5d346f83f6fa27a2", "sha256:6db33440354787f9b7f3a6dbd4febf5d0f93758354060e802f6c06cb493022fe" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==3.2.0" }, "requests": { @@ -90,6 +90,38 @@ "index": "pypi", "version": "==1.7.0" }, + "bandit": { + "hashes": [ + "sha256:2d63a8c573417bae338962d4b9b06fbc6080f74ecd955a092849e1e65c717bd2", + "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a" + ], + "index": "pypi", + "version": "==1.7.4" + }, + "gitdb": { + "hashes": [ + "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd", + "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa" + ], + "markers": "python_version >= '3.6'", + "version": "==4.0.9" + }, + "gitpython": { + "hashes": [ + "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704", + "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.27" + }, + "pbr": { + "hashes": [ + "sha256:cfcc4ff8e698256fc17ea3ff796478b050852585aa5bae79ecd05b2ab7b39b9a", + "sha256:da3e18aac0a3c003e9eea1a81bd23e5a3a75d745670dcf736317b7d966887fdf" + ], + "markers": "python_version >= '2.6'", + "version": "==5.10.0" + }, "pycodestyle": { "hashes": [ "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785", @@ -98,6 +130,61 @@ "markers": "python_version >= '3.6'", "version": "==2.9.1" }, + "pyyaml": { + "hashes": [ + "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", + "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", + "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", + "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", + "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", + "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", + "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", + "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", + "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", + "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", + "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", + "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", + "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", + "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", + "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", + "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", + "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", + "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", + "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", + "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", + "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", + "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", + "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", + "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", + "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", + "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", + "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", + "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", + "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", + "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", + "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", + "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", + "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0" + }, + "smmap": { + "hashes": [ + "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94", + "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936" + ], + "markers": "python_version >= '3.6'", + "version": "==5.0.0" + }, + "stevedore": { + "hashes": [ + "sha256:87e4d27fe96d0d7e4fc24f0cbe3463baae4ec51e81d95fbe60d2474636e0c7d8", + "sha256:f82cc99a1ff552310d19c379827c2c64dd9f85a38bcd5559db2470161867b786" + ], + "markers": "python_version >= '3.8'", + "version": "==4.0.0" + }, "toml": { "hashes": [ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", diff --git a/tweetbot.py b/tweetbot.py index 4e29ec4..7fdf5b4 100644 --- a/tweetbot.py +++ b/tweetbot.py @@ -2,72 +2,95 @@ import os import sys -from typing import Tuple +from typing import List, Tuple import tweepy from time import sleep from random import shuffle - +# Return our credentials from environment variables as UTF-8 bytes. def get_arguments() -> Tuple[bytes, bytes, bytes, bytes]: - consumer_key = os.environ['CONSUMER_KEY'].encode('utf8') - consumer_secret = os.environ['CONSUMER_SECRET'].encode('utf8') - access_token = os.environ['ACCESS_TOKEN'].encode('utf8') - access_token_secret = os.environ['ACCESS_TOKEN_SECRET'].encode('utf8') + consumer_key: bytes = os.environ['CONSUMER_KEY'].encode('utf8') + consumer_secret: bytes = os.environ['CONSUMER_SECRET'].encode('utf8') + access_token: bytes = os.environ['ACCESS_TOKEN'].encode('utf8') + access_token_secret: bytes = os.environ['ACCESS_TOKEN_SECRET'].encode('utf8') return consumer_key, consumer_secret, access_token, access_token_secret -def populate_array(file_lines) -> list: - length = len(file_lines) - - array = [] - - for i in range(length): - array.append(i) +# Copy the file lines to a new List[str] and shuffle it. +def populate_array(file_lines: List[str]) -> List[str]: + array: List[str] = file_lines.copy() + # Scramble like an egg. shuffle(array) return array +# Main function. def main() -> None: - # Access and authorize our Twitter credentials + consumer_key: bytes + consumer_secret: bytes + access_token: bytes + access_token_secret: bytes + + # Access and set authentication method to our Twitter credentials. consumer_key, consumer_secret, access_token, access_token_secret = get_arguments() - auth = tweepy.OAuth1UserHandler(consumer_key=consumer_key, consumer_secret=consumer_secret, - access_token=access_token, access_token_secret=access_token_secret) - api = tweepy.API(auth=auth) + auth: tweepy.OAuth1UserHandler = tweepy.OAuth1UserHandler(consumer_key=consumer_key, consumer_secret=consumer_secret, + access_token=access_token, access_token_secret=access_token_secret) + + # Creating an API object with our authentication method. + api: tweepy.API = tweepy.API(auth=auth) - my_file = open('./everybody.txt', 'r', encoding='utf-8') + array: List[str] + with open('./everybody.txt', 'r', encoding='utf-8') as my_file: + # Read lines one by one from my_file and assign to file_lines variable + file_lines: List[str] = [x.strip() for x in my_file.readlines()] - # Read lines one by one from my_file and assign to file_lines variable - file_lines = [x.strip() for x in my_file.readlines()] + # Close file. + my_file.close() - # Close file. - my_file.close() - - array = populate_array(file_lines) + # Create List[str] from file_lines. + array = populate_array(file_lines) # Driving loop. while True: while array: - tweet = file_lines[array.pop()] + # Grab last element and then remove it. + tweet: str = array.pop() try: + # Output the last element, which will be the tweet. print(tweet) + + # Create a tweet through the API. api.update_status(tweet) + + # Chill out for 1800 seconds. sleep(1800) except tweepy.Forbidden as fe: - print(f"{fe.api_errors}") + # We probably tried to create a duplicate tweet, but say what happened. + print(fe.api_errors) + + # Chill out for 30 seconds. sleep(30) except tweepy.BadRequest as be: - print(f"{be.api_errors}") + # Something is wrong with our client, so say what happened. + print(be.api_errors) + + # Bail. We shouldn't keep trying. sys.exit(1) except tweepy.TweepyException as te: + # Something very unexpected happened, so say what happened. print(te) + + # Bail. We shouldn't keep trying. sys.exit(1) + # Let's do the time warp again. array = populate_array(file_lines) +# Do not delete. if __name__ == '__main__': main()