├── twitter ├── __init__.py ├── config.py ├── __main__.py └── reply_builder.py ├── readme.md ├── Dockerfile ├── .isort.cfg ├── Makefile ├── pyproject.toml ├── tests └── test_reply_builder.py ├── .github └── workflows │ └── deploy.yml ├── .gitignore └── poetry.lock /twitter/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | https://github.com/marketplace/actions/push-to-amazon-ecr 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-alpine 2 | 3 | COPY twitter/*.py /bot/twitter/ 4 | COPY requirements.txt /tmp 5 | RUN pip3 install -r /tmp/requirements.txt 6 | 7 | WORKDIR /bot 8 | CMD ["python3", "-m", "twitter"] -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [isort] 2 | skip_glob = */.*/*,.* 3 | 4 | # Structure 5 | default_section = THIRDPARTY 6 | known_first_party = twitter 7 | 8 | # Import Style 9 | line_length = 80 10 | force_grid_wrap = false 11 | use_parentheses = true 12 | include_trailing_comma = true 13 | combine_as_imports = true 14 | multi_line_output = 3 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | POETRY=poetry 2 | POETRY_RUN=$(POETRY) run 3 | 4 | SOURCE_FILES=$(shell find . -path "./twitter/*.py") 5 | TEST_FILES=$(shell find . -path "./tests/**/*.py") 6 | SOURCES_FOLDER=twitter 7 | 8 | style: 9 | $(POETRY_RUN) isort $(SOURCES_FOLDER) tests 10 | $(POETRY_RUN) black $(SOURCE_FILES) $(TEST_FILES) 11 | 12 | lint: 13 | $(POETRY_RUN) isort $(SOURCES_FOLDER) tests --check-only 14 | $(POETRY_RUN) black $(SOURCE_FILES) $(TEST_FILES) --check 15 | 16 | test: 17 | PYTHONPATH=. $(POETRY_RUN) pytest tests 18 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "latimes-twitter" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Antonio Feregrino "] 6 | license = "MIT" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.9" 10 | tweepy = "^3.10.0" 11 | latimes = "^0.3.0" 12 | emoji-country-flag = "^1.2.3" 13 | python-dateutil = "^2.8.1" 14 | 15 | [tool.poetry.dev-dependencies] 16 | black = {version = "^20.8b1", allow-prereleases = true} 17 | freezegun = "^1.1.0" 18 | isort = "^5.7.0" 19 | pytest = "^6.2.2" 20 | 21 | [build-system] 22 | requires = ["poetry-core>=1.0.0"] 23 | build-backend = "poetry.core.masonry.api" 24 | -------------------------------------------------------------------------------- /twitter/config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | import tweepy 5 | 6 | logger = logging.getLogger() 7 | 8 | 9 | def create_api(): 10 | consumer_key = os.getenv("CONSUMER_KEY") 11 | consumer_secret = os.getenv("CONSUMER_SECRET") 12 | access_token = os.getenv("ACCESS_TOKEN") 13 | access_token_secret = os.getenv("ACCESS_TOKEN_SECRET") 14 | 15 | auth = tweepy.OAuthHandler(consumer_key, consumer_secret) 16 | auth.set_access_token(access_token, access_token_secret) 17 | api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True) 18 | try: 19 | api.verify_credentials() 20 | except Exception as e: 21 | logger.error("Error creating API", exc_info=True) 22 | raise e 23 | logger.info("API created") 24 | return api 25 | -------------------------------------------------------------------------------- /tests/test_reply_builder.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from freezegun import freeze_time 3 | 4 | from twitter.reply_builder import parse_tweet 5 | 6 | 7 | @freeze_time("2021-02-22") 8 | @pytest.mark.parametrize(["input_tweet", "expected_output"],[ 9 | ("mx jueves 10 pm", '22:00 🇲🇽🇨🇷🇸🇻, 23:00 🇨🇴🇪🇨🇵🇪🇵🇦, 01:00+1 🇨🇱🇦🇷🇵🇾🇺🇾, 00:00+1 🇻🇪, 05:00+1 🇬🇶'), 10 | ("domingo 10 pm", '22:00 🇲🇽🇨🇷🇸🇻, 23:00 🇨🇴🇪🇨🇵🇪🇵🇦, 01:00+1 🇨🇱🇦🇷🇵🇾🇺🇾, 00:00+1 🇻🇪, 05:00+1 🇬🇶'), 11 | ("mx Sábado 10:30 pm", '22:30 🇲🇽🇨🇷🇸🇻, 23:30 🇨🇴🇪🇨🇵🇪🇵🇦, 01:30+1 🇨🇱🇦🇷🇵🇾🇺🇾, 00:30+1 🇻🇪, 05:30+1 🇬🇶'), 12 | ("cr jueves 10 pm", '22:00 🇲🇽🇨🇷🇸🇻, 23:00 🇨🇴🇪🇨🇵🇪🇵🇦, 01:00+1 🇨🇱🇦🇷🇵🇾🇺🇾, 00:00+1 🇻🇪, 05:00+1 🇬🇶'), 13 | ("ar jueves 10 pm", '19:00 🇲🇽🇨🇷🇸🇻, 20:00 🇨🇴🇪🇨🇵🇪🇵🇦, 22:00 🇨🇱🇦🇷🇵🇾🇺🇾, 21:00 🇻🇪, 02:00+1 🇬🇶'), 14 | ("gq jueves 10 am", '03:00 🇲🇽🇨🇷🇸🇻, 04:00 🇨🇴🇪🇨🇵🇪🇵🇦, 06:00 🇨🇱🇦🇷🇵🇾🇺🇾, 05:00 🇻🇪, 10:00 🇬🇶'), 15 | ]) 16 | def test_parse_tweet(input_tweet, expected_output): 17 | reply = parse_tweet("@tzconvert " + input_tweet) 18 | 19 | assert reply == expected_output 20 | -------------------------------------------------------------------------------- /twitter/__main__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import tweepy 4 | 5 | from twitter.config import create_api 6 | from twitter.reply_builder import parse_tweet 7 | 8 | logging.basicConfig(level=logging.INFO) 9 | logger = logging.getLogger() 10 | 11 | 12 | class MentionsListener(tweepy.StreamListener): 13 | def __init__(self, api): 14 | self.api = api 15 | self.me = api.me() 16 | 17 | def on_status(self, tweet): 18 | logger.info(f"Processing tweet id {tweet.id}") 19 | if tweet.user.id == self.me.id: 20 | return 21 | 22 | if not tweet.text.lower().startswith("@tzconvert"): 23 | return 24 | 25 | try: 26 | reply = parse_tweet(tweet.text) 27 | self.api.update_status( 28 | status=f"@{tweet.user.screen_name} {reply}", 29 | in_reply_to_status_id=tweet.id, 30 | ) 31 | 32 | except: 33 | logger.error(f"Error while trying to interpret {tweet.text}") 34 | self.api.update_status( 35 | status=f"@{tweet.user.screen_name} ¡ooops! no entendí tu tuit", 36 | in_reply_to_status_id=tweet.id, 37 | ) 38 | 39 | def on_error(self, status): 40 | logger.error(status) 41 | 42 | 43 | def main(): 44 | api = create_api() 45 | tweets_listener = MentionsListener(api) 46 | stream = tweepy.Stream(api.auth, tweets_listener) 47 | stream.filter(track=["@TzConvert"]) 48 | 49 | 50 | if __name__ == "__main__": 51 | main() 52 | -------------------------------------------------------------------------------- /twitter/reply_builder.py: -------------------------------------------------------------------------------- 1 | import flag 2 | from latimes.config import ( 3 | DEFAULT_VALUES, 4 | LatimesConfiguration, 5 | LatimesOutputFormatting, 6 | ) 7 | from latimes.latimes import convert_times 8 | 9 | DEFAULT_TIMEZONE = "America/Mexico_City" 10 | TIMEZONE_ABBREVIATIONS = { 11 | "mx": "America/Mexico_City", 12 | "co": "America/Bogota", 13 | "cl": "America/Santiago", 14 | "ec": "America/Guayaquil", 15 | "pe": "America/Lima", 16 | "ar": "America/Argentina/Buenos_Aires", 17 | "cr": "America/Costa_Rica", 18 | "ve": "America/Caracas", 19 | "gq": "Africa/Malabo", 20 | "sv": "America/El_Salvador", 21 | "py": "America/Asuncion", 22 | "uy": "America/Montevideo", 23 | "pa": "America/Panama", 24 | } 25 | CONVERT_TO = [ 26 | f"{flag.flag(':'+key+':')}:{tz}" for key, tz in TIMEZONE_ABBREVIATIONS.items() 27 | ] 28 | OUTPUT_FORMATTING = LatimesOutputFormatting( 29 | time_format_string="%H:%M", 30 | different_time_joiner=", ", 31 | aggregate=True, 32 | aggregate_joiner="", 33 | ) 34 | 35 | 36 | def parse_tweet(tweet_text: str) -> str: 37 | text = tweet_text[len("@tzconvert") :].strip().lower() 38 | 39 | # Find specific country abbreviation 40 | abbr = text[:3].strip() 41 | if abbr in TIMEZONE_ABBREVIATIONS: 42 | starting_timezone = TIMEZONE_ABBREVIATIONS[abbr] 43 | text = text[3:] 44 | else: 45 | starting_timezone = DEFAULT_TIMEZONE 46 | 47 | text = " ".join(part for part in text.split(" ") if part) 48 | 49 | configuration = LatimesConfiguration( 50 | starting_timezone=starting_timezone, 51 | convert_to=CONVERT_TO, 52 | output_formatting=OUTPUT_FORMATTING, 53 | ) 54 | return convert_times(text, configuration) 55 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Continuous integration 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | name: Build 8 | runs-on: ubuntu-latest 9 | steps: 10 | 11 | - uses: actions/checkout@v2 12 | 13 | - name: Set up Python 14 | uses: actions/setup-python@v1 15 | with: 16 | python-version: 3.9 17 | 18 | - name: Setup environment 19 | run: | 20 | curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python 21 | source $HOME/.poetry/env 22 | poetry --version 23 | 24 | - name: Install dependencies 25 | run: | 26 | source $HOME/.poetry/env 27 | poetry --version 28 | poetry install 29 | 30 | - name: Lint 31 | run: | 32 | source $HOME/.poetry/env 33 | make lint 34 | 35 | - name: Test 36 | run: | 37 | source $HOME/.poetry/env 38 | make test 39 | 40 | - name: Test 41 | run: | 42 | source $HOME/.poetry/env 43 | poetry export -f requirements.txt --output requirements.txt 44 | 45 | - name: Configure AWS credentials 46 | uses: aws-actions/configure-aws-credentials@v1 47 | with: 48 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 49 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 50 | aws-region: us-east-2 51 | 52 | - name: Login to Amazon ECR 53 | id: login-ecr 54 | uses: aws-actions/amazon-ecr-login@v1 55 | 56 | - name: Build, tag, and push image to Amazon ECR 57 | env: 58 | ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} 59 | ECR_REPOSITORY: tzconvert 60 | IMAGE_TAG: ${{ github.sha }} 61 | run: | 62 | docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . 63 | docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest 64 | docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG 65 | docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/pycharm+all,windows 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=pycharm+all,windows 3 | 4 | ### PyCharm+all ### 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 7 | 8 | # User-specific stuff 9 | .idea/**/workspace.xml 10 | .idea/**/tasks.xml 11 | .idea/**/usage.statistics.xml 12 | .idea/**/dictionaries 13 | .idea/**/shelf 14 | 15 | # Generated files 16 | .idea/**/contentModel.xml 17 | 18 | # Sensitive or high-churn files 19 | .idea/**/dataSources/ 20 | .idea/**/dataSources.ids 21 | .idea/**/dataSources.local.xml 22 | .idea/**/sqlDataSources.xml 23 | .idea/**/dynamic.xml 24 | .idea/**/uiDesigner.xml 25 | .idea/**/dbnavigator.xml 26 | 27 | # Gradle 28 | .idea/**/gradle.xml 29 | .idea/**/libraries 30 | 31 | # Gradle and Maven with auto-import 32 | # When using Gradle or Maven with auto-import, you should exclude module files, 33 | # since they will be recreated, and may cause churn. Uncomment if using 34 | # auto-import. 35 | # .idea/artifacts 36 | # .idea/compiler.xml 37 | # .idea/jarRepositories.xml 38 | # .idea/modules.xml 39 | # .idea/*.iml 40 | # .idea/modules 41 | # *.iml 42 | # *.ipr 43 | 44 | # CMake 45 | cmake-build-*/ 46 | 47 | # Mongo Explorer plugin 48 | .idea/**/mongoSettings.xml 49 | 50 | # File-based project format 51 | *.iws 52 | 53 | # IntelliJ 54 | out/ 55 | 56 | # mpeltonen/sbt-idea plugin 57 | .idea_modules/ 58 | 59 | # JIRA plugin 60 | atlassian-ide-plugin.xml 61 | 62 | # Cursive Clojure plugin 63 | .idea/replstate.xml 64 | 65 | # Crashlytics plugin (for Android Studio and IntelliJ) 66 | com_crashlytics_export_strings.xml 67 | crashlytics.properties 68 | crashlytics-build.properties 69 | fabric.properties 70 | 71 | # Editor-based Rest Client 72 | .idea/httpRequests 73 | 74 | # Android studio 3.1+ serialized cache file 75 | .idea/caches/build_file_checksums.ser 76 | 77 | ### PyCharm+all Patch ### 78 | # Ignores the whole .idea folder and all .iml files 79 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 80 | 81 | .idea/ 82 | 83 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 84 | 85 | *.iml 86 | modules.xml 87 | .idea/misc.xml 88 | *.ipr 89 | 90 | # Sonarlint plugin 91 | .idea/sonarlint 92 | 93 | ### Windows ### 94 | # Windows thumbnail cache files 95 | Thumbs.db 96 | Thumbs.db:encryptable 97 | ehthumbs.db 98 | ehthumbs_vista.db 99 | 100 | # Dump file 101 | *.stackdump 102 | 103 | # Folder config file 104 | [Dd]esktop.ini 105 | 106 | # Recycle Bin used on file shares 107 | $RECYCLE.BIN/ 108 | 109 | # Windows Installer files 110 | *.cab 111 | *.msi 112 | *.msix 113 | *.msm 114 | *.msp 115 | 116 | # Windows shortcuts 117 | *.lnk 118 | 119 | # End of https://www.toptal.com/developers/gitignore/api/pycharm+all,windows 120 | 121 | .python-version 122 | *.pyc -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "appdirs" 3 | version = "1.4.4" 4 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 5 | category = "dev" 6 | optional = false 7 | python-versions = "*" 8 | 9 | [[package]] 10 | name = "atomicwrites" 11 | version = "1.4.0" 12 | description = "Atomic file writes." 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 16 | 17 | [[package]] 18 | name = "attrs" 19 | version = "20.3.0" 20 | description = "Classes Without Boilerplate" 21 | category = "dev" 22 | optional = false 23 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 24 | 25 | [package.extras] 26 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] 27 | docs = ["furo", "sphinx", "zope.interface"] 28 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] 29 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] 30 | 31 | [[package]] 32 | name = "black" 33 | version = "20.8b1" 34 | description = "The uncompromising code formatter." 35 | category = "dev" 36 | optional = false 37 | python-versions = ">=3.6" 38 | 39 | [package.dependencies] 40 | appdirs = "*" 41 | click = ">=7.1.2" 42 | mypy-extensions = ">=0.4.3" 43 | pathspec = ">=0.6,<1" 44 | regex = ">=2020.1.8" 45 | toml = ">=0.10.1" 46 | typed-ast = ">=1.4.0" 47 | typing-extensions = ">=3.7.4" 48 | 49 | [package.extras] 50 | colorama = ["colorama (>=0.4.3)"] 51 | d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] 52 | 53 | [[package]] 54 | name = "certifi" 55 | version = "2020.12.5" 56 | description = "Python package for providing Mozilla's CA Bundle." 57 | category = "main" 58 | optional = false 59 | python-versions = "*" 60 | 61 | [[package]] 62 | name = "chardet" 63 | version = "4.0.0" 64 | description = "Universal encoding detector for Python 2 and 3" 65 | category = "main" 66 | optional = false 67 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 68 | 69 | [[package]] 70 | name = "click" 71 | version = "7.1.2" 72 | description = "Composable command line interface toolkit" 73 | category = "main" 74 | optional = false 75 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 76 | 77 | [[package]] 78 | name = "colorama" 79 | version = "0.4.4" 80 | description = "Cross-platform colored terminal text." 81 | category = "dev" 82 | optional = false 83 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 84 | 85 | [[package]] 86 | name = "emoji-country-flag" 87 | version = "1.2.3" 88 | description = "En/Decode unicode country flags emoji" 89 | category = "main" 90 | optional = false 91 | python-versions = "*" 92 | 93 | [[package]] 94 | name = "freezegun" 95 | version = "1.1.0" 96 | description = "Let your Python tests travel through time" 97 | category = "dev" 98 | optional = false 99 | python-versions = ">=3.5" 100 | 101 | [package.dependencies] 102 | python-dateutil = ">=2.7" 103 | 104 | [[package]] 105 | name = "idna" 106 | version = "2.10" 107 | description = "Internationalized Domain Names in Applications (IDNA)" 108 | category = "main" 109 | optional = false 110 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 111 | 112 | [[package]] 113 | name = "iniconfig" 114 | version = "1.1.1" 115 | description = "iniconfig: brain-dead simple config-ini parsing" 116 | category = "dev" 117 | optional = false 118 | python-versions = "*" 119 | 120 | [[package]] 121 | name = "isort" 122 | version = "5.7.0" 123 | description = "A Python utility / library to sort Python imports." 124 | category = "dev" 125 | optional = false 126 | python-versions = ">=3.6,<4.0" 127 | 128 | [package.extras] 129 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"] 130 | requirements_deprecated_finder = ["pipreqs", "pip-api"] 131 | colors = ["colorama (>=0.4.3,<0.5.0)"] 132 | 133 | [[package]] 134 | name = "latimes" 135 | version = "0.3.0" 136 | description = "Convierte tiempos" 137 | category = "main" 138 | optional = false 139 | python-versions = ">=3.6,<4.0" 140 | 141 | [package.dependencies] 142 | click = ">=7.1.2,<8.0.0" 143 | pytz = ">=2021.1,<2022.0" 144 | PyYAML = ">=5.4.1,<6.0.0" 145 | Unidecode = ">=1.2.0,<2.0.0" 146 | 147 | [[package]] 148 | name = "mypy-extensions" 149 | version = "0.4.3" 150 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 151 | category = "dev" 152 | optional = false 153 | python-versions = "*" 154 | 155 | [[package]] 156 | name = "oauthlib" 157 | version = "3.1.0" 158 | description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" 159 | category = "main" 160 | optional = false 161 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 162 | 163 | [package.extras] 164 | rsa = ["cryptography"] 165 | signals = ["blinker"] 166 | signedtoken = ["cryptography", "pyjwt (>=1.0.0)"] 167 | 168 | [[package]] 169 | name = "packaging" 170 | version = "20.9" 171 | description = "Core utilities for Python packages" 172 | category = "dev" 173 | optional = false 174 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 175 | 176 | [package.dependencies] 177 | pyparsing = ">=2.0.2" 178 | 179 | [[package]] 180 | name = "pathspec" 181 | version = "0.8.1" 182 | description = "Utility library for gitignore style pattern matching of file paths." 183 | category = "dev" 184 | optional = false 185 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 186 | 187 | [[package]] 188 | name = "pluggy" 189 | version = "0.13.1" 190 | description = "plugin and hook calling mechanisms for python" 191 | category = "dev" 192 | optional = false 193 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 194 | 195 | [package.extras] 196 | dev = ["pre-commit", "tox"] 197 | 198 | [[package]] 199 | name = "py" 200 | version = "1.10.0" 201 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 202 | category = "dev" 203 | optional = false 204 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 205 | 206 | [[package]] 207 | name = "pyparsing" 208 | version = "2.4.7" 209 | description = "Python parsing module" 210 | category = "dev" 211 | optional = false 212 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 213 | 214 | [[package]] 215 | name = "pysocks" 216 | version = "1.7.1" 217 | description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." 218 | category = "main" 219 | optional = false 220 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 221 | 222 | [[package]] 223 | name = "pytest" 224 | version = "6.2.2" 225 | description = "pytest: simple powerful testing with Python" 226 | category = "dev" 227 | optional = false 228 | python-versions = ">=3.6" 229 | 230 | [package.dependencies] 231 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 232 | attrs = ">=19.2.0" 233 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 234 | iniconfig = "*" 235 | packaging = "*" 236 | pluggy = ">=0.12,<1.0.0a1" 237 | py = ">=1.8.2" 238 | toml = "*" 239 | 240 | [package.extras] 241 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 242 | 243 | [[package]] 244 | name = "python-dateutil" 245 | version = "2.8.1" 246 | description = "Extensions to the standard Python datetime module" 247 | category = "main" 248 | optional = false 249 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 250 | 251 | [package.dependencies] 252 | six = ">=1.5" 253 | 254 | [[package]] 255 | name = "pytz" 256 | version = "2021.1" 257 | description = "World timezone definitions, modern and historical" 258 | category = "main" 259 | optional = false 260 | python-versions = "*" 261 | 262 | [[package]] 263 | name = "pyyaml" 264 | version = "5.4.1" 265 | description = "YAML parser and emitter for Python" 266 | category = "main" 267 | optional = false 268 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 269 | 270 | [[package]] 271 | name = "regex" 272 | version = "2020.11.13" 273 | description = "Alternative regular expression module, to replace re." 274 | category = "dev" 275 | optional = false 276 | python-versions = "*" 277 | 278 | [[package]] 279 | name = "requests" 280 | version = "2.25.1" 281 | description = "Python HTTP for Humans." 282 | category = "main" 283 | optional = false 284 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 285 | 286 | [package.dependencies] 287 | certifi = ">=2017.4.17" 288 | chardet = ">=3.0.2,<5" 289 | idna = ">=2.5,<3" 290 | PySocks = {version = ">=1.5.6,<1.5.7 || >1.5.7", optional = true, markers = "extra == \"socks\""} 291 | urllib3 = ">=1.21.1,<1.27" 292 | 293 | [package.extras] 294 | security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] 295 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 296 | 297 | [[package]] 298 | name = "requests-oauthlib" 299 | version = "1.3.0" 300 | description = "OAuthlib authentication support for Requests." 301 | category = "main" 302 | optional = false 303 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 304 | 305 | [package.dependencies] 306 | oauthlib = ">=3.0.0" 307 | requests = ">=2.0.0" 308 | 309 | [package.extras] 310 | rsa = ["oauthlib[signedtoken] (>=3.0.0)"] 311 | 312 | [[package]] 313 | name = "six" 314 | version = "1.15.0" 315 | description = "Python 2 and 3 compatibility utilities" 316 | category = "main" 317 | optional = false 318 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 319 | 320 | [[package]] 321 | name = "toml" 322 | version = "0.10.2" 323 | description = "Python Library for Tom's Obvious, Minimal Language" 324 | category = "dev" 325 | optional = false 326 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 327 | 328 | [[package]] 329 | name = "tweepy" 330 | version = "3.10.0" 331 | description = "Twitter library for Python" 332 | category = "main" 333 | optional = false 334 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 335 | 336 | [package.dependencies] 337 | requests = {version = ">=2.11.1", extras = ["socks"]} 338 | requests-oauthlib = ">=0.7.0" 339 | six = ">=1.10.0" 340 | 341 | [package.extras] 342 | dev = ["coveralls (>=1.8.2)", "tox (>=2.4.0)"] 343 | test = ["mock (>=1.0.1)", "nose (>=1.3.3)", "vcrpy (>=1.10.3)"] 344 | 345 | [[package]] 346 | name = "typed-ast" 347 | version = "1.4.2" 348 | description = "a fork of Python 2 and 3 ast modules with type comment support" 349 | category = "dev" 350 | optional = false 351 | python-versions = "*" 352 | 353 | [[package]] 354 | name = "typing-extensions" 355 | version = "3.7.4.3" 356 | description = "Backported and Experimental Type Hints for Python 3.5+" 357 | category = "dev" 358 | optional = false 359 | python-versions = "*" 360 | 361 | [[package]] 362 | name = "unidecode" 363 | version = "1.2.0" 364 | description = "ASCII transliterations of Unicode text" 365 | category = "main" 366 | optional = false 367 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 368 | 369 | [[package]] 370 | name = "urllib3" 371 | version = "1.26.3" 372 | description = "HTTP library with thread-safe connection pooling, file post, and more." 373 | category = "main" 374 | optional = false 375 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 376 | 377 | [package.extras] 378 | brotli = ["brotlipy (>=0.6.0)"] 379 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] 380 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 381 | 382 | [metadata] 383 | lock-version = "1.1" 384 | python-versions = "^3.9" 385 | content-hash = "2bc2b3f75684bc0ef2b805f34dc8a5ab0a0049ad214547edb125ff0209662d6e" 386 | 387 | [metadata.files] 388 | appdirs = [ 389 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, 390 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, 391 | ] 392 | atomicwrites = [ 393 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 394 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 395 | ] 396 | attrs = [ 397 | {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, 398 | {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, 399 | ] 400 | black = [ 401 | {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, 402 | ] 403 | certifi = [ 404 | {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, 405 | {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, 406 | ] 407 | chardet = [ 408 | {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, 409 | {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, 410 | ] 411 | click = [ 412 | {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, 413 | {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, 414 | ] 415 | colorama = [ 416 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 417 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 418 | ] 419 | emoji-country-flag = [ 420 | {file = "emoji-country-flag-1.2.3.tar.gz", hash = "sha256:256e47d30fb43bf154f370cc3c9e767f003aeb8653e31ba7b87151669c608e19"}, 421 | {file = "emoji_country_flag-1.2.3-py2.py3-none-any.whl", hash = "sha256:3f6c32699c19489383497865b208260b1d55b8424d66e08049187b13db2f0b8a"}, 422 | ] 423 | freezegun = [ 424 | {file = "freezegun-1.1.0-py2.py3-none-any.whl", hash = "sha256:2ae695f7eb96c62529f03a038461afe3c692db3465e215355e1bb4b0ab408712"}, 425 | {file = "freezegun-1.1.0.tar.gz", hash = "sha256:177f9dd59861d871e27a484c3332f35a6e3f5d14626f2bf91be37891f18927f3"}, 426 | ] 427 | idna = [ 428 | {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, 429 | {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, 430 | ] 431 | iniconfig = [ 432 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 433 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 434 | ] 435 | isort = [ 436 | {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"}, 437 | {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"}, 438 | ] 439 | latimes = [ 440 | {file = "latimes-0.3.0-py3-none-any.whl", hash = "sha256:eed650fa5789781768d33e826171850c4e897bb49f13053f045f0cf8b939b2f2"}, 441 | {file = "latimes-0.3.0.tar.gz", hash = "sha256:2dc265797527047902d24bfd4201dc7b467e9417d596a9b7b1719dcc5d49b7c1"}, 442 | ] 443 | mypy-extensions = [ 444 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 445 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 446 | ] 447 | oauthlib = [ 448 | {file = "oauthlib-3.1.0-py2.py3-none-any.whl", hash = "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"}, 449 | {file = "oauthlib-3.1.0.tar.gz", hash = "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889"}, 450 | ] 451 | packaging = [ 452 | {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, 453 | {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, 454 | ] 455 | pathspec = [ 456 | {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, 457 | {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, 458 | ] 459 | pluggy = [ 460 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 461 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 462 | ] 463 | py = [ 464 | {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, 465 | {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, 466 | ] 467 | pyparsing = [ 468 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, 469 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, 470 | ] 471 | pysocks = [ 472 | {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, 473 | {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, 474 | {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, 475 | ] 476 | pytest = [ 477 | {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"}, 478 | {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"}, 479 | ] 480 | python-dateutil = [ 481 | {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, 482 | {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, 483 | ] 484 | pytz = [ 485 | {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, 486 | {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, 487 | ] 488 | pyyaml = [ 489 | {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, 490 | {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, 491 | {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, 492 | {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, 493 | {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, 494 | {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, 495 | {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, 496 | {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, 497 | {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, 498 | {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, 499 | {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, 500 | {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, 501 | {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, 502 | {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, 503 | {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, 504 | {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, 505 | {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, 506 | {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, 507 | {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, 508 | {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, 509 | {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, 510 | ] 511 | regex = [ 512 | {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, 513 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, 514 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, 515 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, 516 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, 517 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, 518 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, 519 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, 520 | {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, 521 | {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, 522 | {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, 523 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, 524 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, 525 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, 526 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, 527 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, 528 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, 529 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, 530 | {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, 531 | {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, 532 | {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, 533 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, 534 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, 535 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, 536 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, 537 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, 538 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, 539 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, 540 | {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, 541 | {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, 542 | {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, 543 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, 544 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, 545 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, 546 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, 547 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, 548 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, 549 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, 550 | {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, 551 | {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, 552 | {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, 553 | ] 554 | requests = [ 555 | {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, 556 | {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, 557 | ] 558 | requests-oauthlib = [ 559 | {file = "requests-oauthlib-1.3.0.tar.gz", hash = "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"}, 560 | {file = "requests_oauthlib-1.3.0-py2.py3-none-any.whl", hash = "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d"}, 561 | {file = "requests_oauthlib-1.3.0-py3.7.egg", hash = "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"}, 562 | ] 563 | six = [ 564 | {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, 565 | {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, 566 | ] 567 | toml = [ 568 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 569 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 570 | ] 571 | tweepy = [ 572 | {file = "tweepy-3.10.0-py2.py3-none-any.whl", hash = "sha256:5e22003441a11f6f4c2ea4d05ec5532f541e9f5d874c3908270f0c28e649b53a"}, 573 | {file = "tweepy-3.10.0.tar.gz", hash = "sha256:76e6954b806ca470dda877f57db8792fff06a0beba0ed43efc3805771e39f06a"}, 574 | ] 575 | typed-ast = [ 576 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, 577 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, 578 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, 579 | {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, 580 | {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, 581 | {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, 582 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, 583 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, 584 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, 585 | {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, 586 | {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, 587 | {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, 588 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, 589 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, 590 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, 591 | {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, 592 | {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, 593 | {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, 594 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, 595 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, 596 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, 597 | {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, 598 | {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, 599 | {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, 600 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, 601 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, 602 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, 603 | {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, 604 | {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, 605 | {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, 606 | ] 607 | typing-extensions = [ 608 | {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, 609 | {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, 610 | {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, 611 | ] 612 | unidecode = [ 613 | {file = "Unidecode-1.2.0-py2.py3-none-any.whl", hash = "sha256:12435ef2fc4cdfd9cf1035a1db7e98b6b047fe591892e81f34e94959591fad00"}, 614 | {file = "Unidecode-1.2.0.tar.gz", hash = "sha256:8d73a97d387a956922344f6b74243c2c6771594659778744b2dbdaad8f6b727d"}, 615 | ] 616 | urllib3 = [ 617 | {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"}, 618 | {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"}, 619 | ] 620 | --------------------------------------------------------------------------------