├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE ├── README.md ├── action.yml ├── funfacts └── funfacts.txt ├── images ├── quote-readme.png └── result.png ├── main.py ├── quotes └── quotes.txt ├── requirements.txt ├── scripts ├── scrape_fun_facts.py └── scrape_quotes.py └── tests ├── __init__.py ├── test_main.py ├── test_scrape_funfacts.py └── test_scrape_quotes.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # .DS_Store 132 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.7" 4 | install: 5 | - pip install -r requirements.txt 6 | script: 7 | - python -m unittest discover -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | 3 | # Install dependencies. 4 | ADD requirements.txt /requirements.txt 5 | RUN pip install -r requirements.txt 6 | 7 | ADD quotes/quotes.txt /quotes/quotes.txt 8 | ADD funfacts/funfacts.txt /funfacts/funfacts.txt 9 | 10 | # Copy code. 11 | ADD main.py /main.py 12 | 13 | CMD ["python", "/main.py"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Siddharth Chandra 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Random Quote/Fact on README [![Travis CI Build](https://travis-ci.org/siddharth2016/quote-readme.svg?branch=main)](https://travis-ci.org/github/siddharth2016/quote-readme) 2 | 3 | 4 | ![Github Socialify](https://socialify.git.ci/siddharth2016/quote-readme/image?font=Source%20Code%20Pro&forks=1&issues=1&pattern=Brick%20Wall&stargazers=1&theme=Dark) 5 | 6 | --- 7 | 8 | ## GitHub Action that allows you to place a random quote/fact on your README 9 | 10 | ![Random Quote On Readme Result](images/result.png) 11 | 12 | --- 13 | 14 | ## Random Quote/Fact on your (Profile) Readme 15 | 16 | ### How To Use This Action 17 | 18 | There is a short tutorial with enough steps for you to get started with this not-so-useful GitHub Action. Check that out [here](https://chandraji.dev/quote-readme-see-wonderful-quotesfun-facts-on-your-github-profile-readme). 19 | 20 | If you want to get an in-depth idea of the usage of this action, please follow the below points. 21 | 22 | ### Prepare Your Repository 23 | 24 | 1. You need to update the markdown file(.md) with 2 comments. You can refer to [here](#update-your-readme) for updating it. 25 | 2. **Optional** You'll need a GitHub API Token with `repo` scope from [here](https://github.com/settings/tokens) if you're running the action for a non-profile repository. 26 | - You can use [this](#other-repository-not-profile) example to work it out. 27 | 3. You can follow any one example below according to your needs to get started! 28 | - Use [this](#profile-repository) on Profile Repository. 29 | - Use [this](#other-repository-not-profile) on any other Repository. 30 | 4. It is better to run the Action on your Profile Repository since you won't be needing a GitHub Access Token! 31 | 5. Check [this](#examples) to see available options while creating a workflow for this action. 32 | 33 | ### Errors And Workarounds 34 | 35 | If you are facing a GithubException "Resource not accessible by integration", you may want to check your repository permissions or GitHub token permissions. 36 | 37 | For repository permissions (Thank you [@jaborjkath](https://github.com/jaborjkath) for bringing this to my attention): 38 | To enable read and write permissions from the relevant repository settings (top right corner) → Actions (left navigation bar) → General → Workflow permissions section. 39 | You can find more information [here](https://stackoverflow.com/questions/61989951/github-action-workflow-not-running/77167633#77167633). 40 | 41 | For GitHub token permissions you can refer [here](https://docs.github.com/en/actions/security-guides/automatic-token-authentication). 42 | 43 | --- 44 | 45 | ### Update Your Readme 46 | 47 | Add a comment to your `README.md` like this: 48 | 49 | ```md 50 | 51 | 52 | ``` 53 | 54 | You can place these 2 lines anywhere you want quotes/facts to be displayed. 55 | 56 | --- 57 | 58 | ### Profile Repository 59 | 60 | _If you're executing the workflow on your Profile Repository (`/`)_ 61 | 62 | You wouldn't need a GitHub Access Token since GitHub Actions already makes one for you. 63 | 64 | Please follow the steps below: 65 | 66 | 1. Go to your `//actions`, hit `New workflow`, then `set up a workflow yourself`, delete all the default content github made for you. 67 | 2. Copy the following code and paste it to your new workflow you created at step 1, commit the workflow and name it whatever you like ! 68 | 69 | ```yml 70 | name: Update Quote Readme 71 | 72 | on: 73 | workflow_dispatch: 74 | schedule: 75 | # Runs at 2 UTC everyday 76 | - cron: "0 2 * * *" 77 | 78 | jobs: 79 | update-readme: 80 | name: Update Quote README 81 | runs-on: ubuntu-latest 82 | steps: 83 | - uses: siddharth2016/quote-readme@main 84 | ``` 85 | 86 | 3. There is another tag as well you can use, `OPTION` that would allow you to specify what you want either a quote or a fact to be displayed, by default it is `both`. Check [examples](#examples) for more. 87 | 4. Add a comment to your `README.md` like this: 88 | 89 | ```md 90 | 91 | 92 | ``` 93 | 94 | 5. Go to Workflows menu (mentioned in step 1), click `Update Quote Readme`, click `Run workflow`. 95 | 6. Go to your profile page, you will be able to see a random quote/fact wherever you placed [this](#update-your-readme) comment on README. 96 | 97 | --- 98 | 99 | ### Other Repository (not Profile) 100 | 101 | _If you're executing the workflow on another repo other than (`/`)_ 102 | 103 | You'll need to get a [GitHub Access Token](https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token) with a `repo` scope. 104 | 105 | You need to save the GitHub API Token in the repository secrets. You can find that in the Settings of your Repository. 106 | 107 | 1. Go to your `//actions`, hit `New workflow`, then `set up a workflow yourself`, delete all the default content github made for you. 108 | 2. Copy the following code and paste it to your new workflow you created at step 1, commit the workflow with whatever name you like ! 109 | 110 | ```yml 111 | name: Update Quote Readme 112 | 113 | on: 114 | workflow_dispatch: 115 | schedule: 116 | # Runs at 2 UTC everyday 117 | - cron: "0 2 * * *" 118 | 119 | jobs: 120 | update-readme: 121 | name: Update Quote README 122 | runs-on: ubuntu-latest 123 | steps: 124 | - uses: siddharth2016/quote-readme@main 125 | with: 126 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 127 | REPOSITORY: / # No need to mention this if workflow present in current non profile repo. 128 | ``` 129 | 130 | 3. There is another tag as well you can use, `OPTION` that would allow you to specify what you want either a quote or a fact to be displayed, by default it is `both`. Check [examples](#examples) for more. 131 | 4. Add a comment to your `README.md` like this: 132 | 133 | ```md 134 | 135 | 136 | ``` 137 | 138 | 5. Go to Workflows menu (mentioned in step 1), click `Update Quote Readme`, click `Run workflow`. 139 | 6. Go to your profile page, you will be able to see a random quote/fact wherever you placed [this](#update-your-readme) comment on README. 140 | 141 | --- 142 | 143 | ### Examples 144 | 145 | 1. If you want to use this action for a README that is not present in current workflow repository. 146 | 147 | ```yml 148 | - uses: siddharth2016/update-readme-image@main 149 | with: 150 | GH_TOKEN: ${{ secrets.GH_TOKEN }} # Needed if README repository is not profile repo 151 | REPOSITORY: / 152 | ``` 153 | 154 | Using `REPOSITORY` will change README present in that repository head. 155 | 156 | For example, if your workflow is present in `/repo1` and you want to update README present in `/repo2`, then assign `REPOSITORY` to `/repo2` in workflow at `/repo1`. 157 | 158 | 2. You can specify a commit message to override the default _"Update with quote-readme"_. 159 | 160 | ```yml 161 | - uses: siddharth2016/update-readme-image@main 162 | with: 163 | GH_TOKEN: ${{ secrets.GH_TOKEN }} # Needed if README repository is not profile repo 164 | REPOSITORY: / # Needed if README repository is not current repo 165 | COMMIT_MESSAGE: # default - Update with quote-readme 166 | ``` 167 | 168 | 3. You can also choose if you only want either a random `quote` or a random `funfact` to appear on your readme, by default it is `both`. 169 | 170 | ```yml 171 | - uses: siddharth2016/update-readme-image@main 172 | with: 173 | GH_TOKEN: ${{ secrets.GH_TOKEN }} # Needed if README repository is not profile repo 174 | REPOSITORY: / # Needed if README repository is not current repo 175 | COMMIT_MESSAGE: # default - Update with quote-readme 176 | OPTION: both # default - both, can be one of (quote, funfact, both), if 'both' then will display either a quote or a fact 177 | ``` 178 | 179 | --- 180 | 181 | ### Tests 182 | 183 | To run tests simply execute the following in the directory containing `main.py`: 184 | 185 | ```bash 186 | python -m unittest discover 187 | ``` 188 | 189 | --- 190 | 191 | #### Another intriguing action you would want to use - [update-readme-image](https://github.com/marketplace/actions/update-image-readme) 192 | 193 | #### Check out the [scripts](https://github.com/siddharth2016/quote-readme/tree/main/scripts) folder to know more about how quotes/facts were retrieved 194 | 195 | #### If you liked this Action and want to contribute to upgrade this utility, please create an issue or throw a PR ! 196 | 197 | --- 198 | 199 | #### Inspired From 200 | 201 | [athul/waka-readme](https://github.com/athul/waka-readme) 202 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "Quote - README" 2 | author: Siddharth Chandra 3 | description: "Update a section with random quote/fun-fact on your Readme" 4 | 5 | inputs: 6 | GH_TOKEN: 7 | description: "GitHub access token with Repo scope" 8 | required: true 9 | default: ${{ github.token }} 10 | 11 | REPOSITORY: 12 | description: "Your GitHub repository" 13 | default: ${{ github.repository }} 14 | required: false 15 | 16 | OPTION: 17 | description: "Option for quote, fun-fact or both, it can take - quote, funfact or both" 18 | default: "both" 19 | required: false 20 | 21 | COMMIT_MESSAGE: 22 | description: "Add a commit message of your choice" 23 | default: "Update with quote-readme" 24 | required: false 25 | 26 | runs: 27 | using: "docker" 28 | image: "Dockerfile" 29 | 30 | branding: 31 | icon: "bookmark" 32 | color: "orange" 33 | -------------------------------------------------------------------------------- /funfacts/funfacts.txt: -------------------------------------------------------------------------------- 1 | The first electronic computer ENIAC weighed more than 27 tons and took up 1800 square feet. 2 | TYPEWRITER is the longest word that you can write using the letters only on one row of the keyboard of your computer. 3 | The password for the computer controls of nuclear-tipped missiles of the U.S was 00000000 for eight years. 4 | A computer worm was present before that could access your Windows XP OS, could download a patch from Microsoft to exist the vulnerability as used it to infect the system and after delete itself. 5 | Approximately 70% of virus writers are said to work under contract for organized crime syndicates. 6 | HP, Microsoft and Apple have one very interesting thing in common – they were all started in a garage. 7 | Amazon was a hard cover book seller, but actually now sells more e-books than hard covers 8 | An average person normally blinks 20 times a minute, but when using a computer he/she blinks only 7 times a minute. 9 | More than 80% of the emails sent daily are spams. 10 | In 2010, a high school named Lower Merion School District in Pennsylvania issued a MacBook to each of its 2,306 students, then remotely activated the webcams to spy on the students at home. 11 | The fact that keyboard have ‘Q’ ‘W’ ‘E’ ‘R’ ‘T’ ‘Y’ types of button: When keyboard was invented, it had buttons in alphabetical order, as a result, the typing speed was too fast and the computer used to hang. So, to reduce the speed of a person, qwerty keyboard were invented. 12 | In 2005, Sony illegally installed rootkits on 22 million computers to prevent the users from ripping copyrighted music, and could not be uninstalled. It also reported user’s listening habits back to Sony. Ironically, the code itself contained open source software, and so infringed copyright. 13 | 2012 was the year a hacker group took down Pope John’s website because a food company spent over two hours to deliver as expected. The hacker group was called UGNazi. 14 | In Windows 98, minimized windows are actually moved far away outside the average monitor’s resolution. 15 | It took Pixar 29 hours to render a single frame from Monster’s University. If done on a single CPU it would have taken 10,000 years to finish. 16 | IBM 5120 from 1980 was the heaviest desktop computer ever made. It weighed about 105 pounds, not including the 130 pounds external floppy drive. 17 | A 15 year old hacked NASA computers and caused a 21-day shutdown of their computers. 18 | The computer in your cell phone today is million times cheaper and a thousands times more powerful and about a hundred thousands times smaller than the one computer at MIT in 1965. 19 | Only about 10% of the world’s currency is physical money, the rest only exists on computers. 20 | Doug Engelbart invented the first computer mouse in around 1964 which was made of wood. 21 | In 1960, the computer at NORAD warned with 99.9% certainty that the Soviets had just launched a full-scale missile attack against North America. NORAD later discovered that the Early Warning System in Greenland had interpreted the moon rising over Norway as a missile attack from Siberia. 22 | In 1833, Charles Babbage invented all the parts a modern computer uses, but it wasn’t until 120 years later that the first modern computers were invented. 23 | There are more than 5000 new computer viruses are released every month. 24 | The house where Bill Gates lives, was designed using a Macintosh computer. 25 | Web Arx security says more than 20,000 websites are hacked each day and most from the US 26 | YouTube was founded by 3 former employees of PayPal. 27 | The first ever hard disk drive was made in 1979, and could hold only 5MB of data. 28 | In 2012, the founder of McAfee Antivirus, John McAfee was asked if he personally uses McAfee anti-virus, he replied by saying “I take it off,” and that “It’s too annoying.” 29 | China has the highest number of internet users in the whole world with over 746 million active users. 30 | There are around  3.58 billion internet users worldwide as of 2017 according to statista. 31 | The first 1GB hard disk drive was announced in 1980 which weighed about 550 pounds, and had a price tag of $40,000. 32 | According to statista, by 2023, over 50 billion devices will be connected on the internet. 33 | The woman who rented her garage to Larry Page and Sergey Brin in 1998 when they were creating Google later became the CEO of YouTube. 34 | There are over 1.5 billion instant messaging id’s in the world over. 35 | The first webcam was used at Cambridge University. Its purpose was to monitor a coffee maker so they didn’t waste trips to an empty pot. 36 | A group of 12 engineers designed IBM PC and they were called as “The Dirty Dozen”. 37 | Well, there are two games that were the first ever made in the US called Asteroids and Lunar Lander in 1980. 38 | Mircosoft included Solitaire in their operating systems “to soothe people intimidated by the operating system” and introduce users to graphic user interfaces and taught them how to use a mouse. 39 | The Space Shuttle never flew on new year’s day or eve because its computers couldn’t handle a year rollover. 40 | The original name of Windows was Interface Manager. 41 | Konrad Zuse is the inventor of the first programmable computer in the world. He did it in 1936 and named the computer as Z1. Konrad Zuse 42 | The first-ever registered domain name was Symbolics.com for free. 43 | All the domain names such as Google, Log In or Sign Up were free until 1995, but now everyone has to pay for every new domain name. 44 | Russians made a computer that ran on water in the mid of 1936. 45 | A professional typist types fast and types great amount of words daily. If we measure this as distance, than it will become 12.6 miles a day for the fingers of the typist to cover each day. 46 | The original Halo was 3rd person and designed for Mac. In 2000 Microsoft bought Bungie and made it an exclusive for the original Xbox. 47 | During IBM Watson’s Jeopardy Game, it stored all 15 terabytes of its knowledge in RAM, including every page of Wikipedia in existence. 48 | 500 hours of Video are uploaded to Facebook every minute according to Forecast. 49 | E-Mail was invented before Internet. Shocked!!!! ” I also got shocked after hearing this.” 50 | There is a website called “The Useless Web” . This is the last treatment for your boredom. If you ever feel bored please visit. 51 | The first Apple computer ever made by Steve Jobs and Steve Wozniak was made from old parts they collected for free from their staff! 52 | Only 2 out of the top 500 supercomputers run on Windows, and 485 are Linux. 53 | IBM was so powerful in 1983 that people feared that its PCjr home computer would destroy Apple, Commodore, and all other competitors. The PCjr became “one of the biggest flops in the history of computing”. 54 | IMDb is one of the oldest websites on the internet, and began on Usenet in 1990 as a list of “actresses with beautiful eyes.” 55 | No human has won a tournament standard chess game against a high spec computer since 2005. 56 | A programmer developed an operating system called TempleOS in Hospitalized for mental health problems, he believes that TempleOS is literally the Third Temple as biblically prophesied. Per God’s “instructions,” the OS uses a 640×480, 16 color display, and uses the language HolyC. 57 | The first word spoken on the internet was “lo”. It was supposed to be “login” but the computer crashed after the first two letters. 58 | Windows 95 was the second most installed piece of software on computers in 1995, video game DOOM was first. 59 | Gaming computers heat a room just as efficiently as a space heater does. 60 | The Space Invaders game was intended to always be played at the same speed, but as you destroy more aliens, the computer can render faster. This is why the aliens speed up as you near the end of the level. 61 | There was a time when AMD and Intel CPUs used the same socket (Socket 7) and could run on the same motherboard. 62 | Hard disks are so sensitive to vibration, that just screaming at them diminishes their performance. 63 | Sony released a kit that allows PS2s (Linux for PlayStation 2) to be used as a personal computer. 64 | There is a video game, called “Lose/Lose” that deletes a random file on your computer every time you kill an enemy. 65 | As computers run, they get hot. Computers have fans to keep them cool. 66 | elgoog.im (Google spelled backwards) is a mirrored website of Google Search with horizontally flipped search results, also known as a “Google mirror”. An unofficial elgooG website was created by All Too Flat “for fun”, which started to gain popularity in 2002 67 | When you’re all grown up and working and you use a computer each day, your hands would have traveled 12.6 miles (about 20km) per day! 68 | Whether you use Mozilla, Chrome Explore, please know that Mosaic was the first browser in  Just when I was born. 69 | The US Federal Register is still using floppy disks sent by courier because a secure e-mail system is “too expensive”. 70 | If you open up the case of the original Macintosh, there are 47 signatures there, which are from each member of Apple’s Macintosh division in Interesting? 71 | During the production of Toy Story 2, Pixar accidentally deleted the entire movie from its servers. The movie was saved by an employee, a new mother, who worked from home and had the data saved on her personal computer. 72 | Lenovo stands for ‘new legend’. ‘Le’ for legend, and ‘novo’ stands for new. 73 | Facebook has over a billion users. If it was a country it would be the third largest in the world. 74 | American mathematician Marion Tinsley played checkers for 45 years and lost only 7 games. He once beat a computer program, and later analysis showed that Tinsley had played the only possible winning strategy from 64 moves out. 75 | Apple’s first computer, the Apple I, went on sale in 1976 for $666.66 because Steve Wozniak liked repeating digits and found them easier to type. He said he was unaware of any Satanic connotations with the number. 76 | The term “World Wide Web” was invented by Tim Berners in 1990. 77 | The very first computer was an abacus invested 500 B.C in Babylon made of string and beads whose main purpose was to count. 78 | Around 50% of all Wikipedia vandalism is caught by a single computer program with more than 90% accuracy. 79 | If there was a computer as powerful as the human brain, it would be able to do 38 thousand trillion operations per second and hold more than 3580 terabytes of memory. 80 | One of the first instances of a stored computer program was in 1801 when Joseph Marie Jacquard demonstrated a loom that wove fabrics based on hole-punched cards that were fed into the machine. 81 | Steve Jobs wanted to hide a man wearing a fedora on the first Mac. Dubbed “Mr. Macintosh,” the character would appear after opening the menu bar several thousand times then quickly disappear, leaving users to question their sanity. The idea was scrapped due to Mac’s paltry 128KB of RAM. 82 | CPU manufacturing is so unpredictable that every chip must be tested since the majority of finished chips are defective. Those that survive are assigned a model number and price reflecting their maximum safe performance. 83 | There is a programming language called INTERCAL which has keywords like IGNORE, PLEASE , FORGET. If you don’t use PLEASE enough times while coding, Compiler rejects the code. 84 | Computers have memory or RAM, which stores items on the computer when they’re not in use. The processor stores everything your computer needs to run. 85 | In 2009, computer scientists created a system that composes a realistic picture from a simple freehand sketch, pulling photos from the internet: Sketch2Photo. 86 | HDMI charges its licensed manufacturers $10,000 per year plus $0.15 per cable, reduced to $0.05 if the HDMI logo is on the socket. 87 | In May 1997, an IBM supercomputer known as Deep Blue beat then chess world champion Garry Kasparov, who had once bragged that he would never lose to a machine. After 15 years, it was discovered that the critical move made by Deep Blue was due to a bug in its software. 88 | The Ultra NVidia GeForce 6800 video card was built with 222 million transistors and considered among the best todate. 89 | The first microprocessor created by Intel was the It was designed for a calculator, and in that time nobody imagined where it would lead. 90 | The first bug in a computer was a dead moth found shorting a relay in the Harvard Mark II computer in 1947 91 | Windows doesn’t allow for creation of folders tagged CON, PRN, AUX, or NUL. These are keywords reserved by DOS. 92 | Mortal Kombat II was so popular when it hit the arcades that several of the machines were later installed with deadlock security panels on the back to prevent thieves from ripping the game’s motherboard straight out of the machine and taking it home. 93 | 4004 was the name given to the first microprocessor by Intel. 94 | The worst breach of U.S. military computers in history happened when someone picked up a memory stick (infected by a foreign intelligence agency) they found in the parking lot and plugged it into their computer, which was attached to United States Central Command. 95 | According to a survey, most of the apps in your android device leaks your data, so be aware. 96 | The microcontroller inside a MacBook charger is about as powerful as the original Macintosh computer. 97 | Tandy TRS-80 Model I computer radiated so much interference that many games were designed so that an AM radio next to the computer could be used to provide sounds. 98 | An Apple laptop stinks. One 2001 iBook model used a glue that, after 12-18 months, may begin to smell like human body odor. It is so strong that repairs are difficult because the smell makes people nauseous. 99 | CAPTCHA is an acronym for “Completely Automated Public Turing test to tell Computers and Humans Apart” 100 | -------------------------------------------------------------------------------- /images/quote-readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siddharth2016/quote-readme/a0d04b5b5863ae4a82e07de7a8aa0e3b0367fc51/images/quote-readme.png -------------------------------------------------------------------------------- /images/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siddharth2016/quote-readme/a0d04b5b5863ae4a82e07de7a8aa0e3b0367fc51/images/result.png -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #main.py 2 | """ 3 | Action script to select a random quote/fun-fact and put it on given repository's README. 4 | """ 5 | 6 | import os 7 | import re 8 | import sys 9 | import random 10 | import base64 11 | from typing import List 12 | from github import Github, GithubException 13 | 14 | STARTS_WITH = "" 15 | ENDS_WITH = "" 16 | REPL_PATTERN = f"{STARTS_WITH}[\\s\\S]+{ENDS_WITH}" 17 | 18 | REPOSITORY = os.getenv("INPUT_REPOSITORY") 19 | GH_TOKEN = os.getenv("INPUT_GH_TOKEN") 20 | COMMIT_MSG = os.getenv("INPUT_COMMIT_MESSAGE") 21 | OPTION = os.getenv("INPUT_OPTION") 22 | 23 | QUOTES_PATH = "/quotes/quotes.txt" 24 | FUNFACTS_PATH = "/funfacts/funfacts.txt" 25 | 26 | 27 | def get_quotes() -> List[str]: 28 | """ 29 | Get quotes from quotes/quotes.txt, return a list. 30 | """ 31 | global QUOTES_PATH 32 | quotes = [] 33 | with open(QUOTES_PATH, "r") as file: 34 | quotes.extend(file.readlines()) 35 | random.shuffle(quotes) 36 | return quotes 37 | 38 | 39 | def get_funfacts() -> List[str]: 40 | """ 41 | Get funfacts from funfacts/funfacts.txt, return a list. 42 | """ 43 | global FUNFACTS_PATH 44 | funfacts = [] 45 | with open(FUNFACTS_PATH, "r") as file: 46 | funfacts.extend(file.readlines()) 47 | random.shuffle(funfacts) 48 | return funfacts 49 | 50 | 51 | def get_option_list(OPTION): 52 | """ 53 | Utility to get text list for corresponding given option. 54 | """ 55 | text_list = [] 56 | if OPTION == 'quote': 57 | text_list.extend(get_quotes()) 58 | elif OPTION == 'funfact': 59 | text_list.extend(get_funfacts()) 60 | elif OPTION == 'both': 61 | text_list.extend(get_quotes()) 62 | text_list.extend(get_funfacts()) 63 | random.shuffle(text_list) 64 | return text_list 65 | 66 | 67 | def get_quote_funfact(text_list: List[str]) -> str: 68 | """ 69 | Utility to get random text from given list. 70 | """ 71 | return random.choice(text_list) 72 | 73 | 74 | def get_text_to_display() -> str: 75 | """ 76 | Get text to display on readme, depending on option. 77 | """ 78 | global OPTION 79 | text_list = get_option_list(OPTION) 80 | text_to_display = get_quote_funfact(text_list) 81 | text_to_display = re.sub('[\n]', '', text_to_display) 82 | text_to_display = re.sub('[\xa0]', ' ', text_to_display) 83 | text_to_display = f"❝{text_to_display}❞" 84 | return text_to_display 85 | 86 | 87 | def decode_readme(data: str) -> str: 88 | """ 89 | Decode the contents of old readme. 90 | """ 91 | decoded_bytes = base64.b64decode(data) 92 | return str(decoded_bytes, 'utf-8') 93 | 94 | 95 | def generate_new_readme(readme: str, i_tag: str) -> str: 96 | """ 97 | Generate a new Readme. 98 | """ 99 | update_readme_with = f"{STARTS_WITH}\n{i_tag}\n{ENDS_WITH}" 100 | return re.sub(REPL_PATTERN, update_readme_with, readme) 101 | 102 | 103 | if __name__ == "__main__": 104 | g = Github(GH_TOKEN) 105 | try: 106 | readme_repo = g.get_repo(REPOSITORY) 107 | except GithubException: 108 | print("Authentication Error. Try saving a GitHub Token in your Repo Secrets or Use the GitHub Actions Token, which is automatically used by the action.") 109 | sys.exit(1) 110 | text_to_display = get_text_to_display() 111 | readme_obj = readme_repo.get_readme() 112 | readme_content = readme_obj.content 113 | readme_content_decoded = decode_readme(readme_content) 114 | new_readme = generate_new_readme(readme=readme_content_decoded, i_tag=text_to_display) 115 | if readme_content_decoded != new_readme: 116 | readme_repo.update_file(path=readme_obj.path, message=COMMIT_MSG, 117 | content=new_readme, sha=readme_obj.sha) 118 | print("Success") 119 | else: 120 | print('No change') 121 | -------------------------------------------------------------------------------- /quotes/quotes.txt: -------------------------------------------------------------------------------- 1 | “I do not fear computers. I fear lack of them.”— Isaac Asimov  2 | “A computer once beat me at chess, but it was no match for me at kick boxing.”— Emo Philips  3 | “Computer Science is no more about computers than astronomy is about telescopes.”— Edsger W. Dijkstra  4 | “The computer was born to solve problems that did not exist before.”— Bill Gates     5 | “Software is like entropy: It is difficult to grasp, weighs nothing, and obeys the Second Law of Thermodynamics; i.e., it always increases.”— Norman Augustine    6 | “Software is a gas; it expands to fill its container.”— Nathan Myhrvold   7 | “All parts should go together without forcing.  You must remember that the parts you are reassembling were disassembled by you.  Therefore, if you can’t get them together again, there must be a reason.  By all means, do not use a hammer.”— IBM Manual, 1925   8 | “Standards are always out of date.  That’s what makes them standards.”— Alan Bennett    9 | “Physics is the universe’s operating system.”— Steven R Garman    10 | “It’s hardware that makes a machine fast.  It’s software that makes a fast machine slow.”— Craig Bruce    11 | “Imagination is more important than knowledge.  For knowledge is limited, whereas imagination embraces the entire world, stimulating progress, giving birth to evolution.”— Albert Einstein    12 | “The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge.”— Stephen Hawking    13 | “The more you know, the more you realize you know nothing.”— Socrates    14 | “Tell me and I forget.  Teach me and I remember.  Involve me and I learn.”— Benjamin Franklin    15 | “Real knowledge is to know the extent of one’s ignorance.”— Confucius    16 | “If people never did silly things, nothing intelligent would ever get done.”— Ludwig Wittgenstein    17 | “Getting information off the Internet is like taking a drink from a fire hydrant.”— Mitchell Kapor  18 | “If you think your users are idiots, only idiots will use it.”— Linus Torvalds    19 | “From a programmer’s point of view, the user is a peripheral that types when you issue a read request.”— P. Williams    20 | “Where is the ‘any’ key?”— Homer Simpson, in response to the message, “Press any key”    21 | “Computers are good at following instructions, but not at reading your mind.”— Donald Knuth    22 | “There is only one problem with common sense; it’s not very common.”— Milt Bryce    23 | “Your most unhappy customers are your greatest source of learning.”— Bill Gates    24 | “Let us change our traditional attitude to the construction of programs: Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.”— Donald E. Knuth    25 | “The Internet?  We are not interested in it.”— Bill Gates, 1993    26 | “The best way to get accurate information on Usenet is to post something wrong and wait for corrections.”— Matthew Austern    27 | “The most likely way for the world to be destroyed, most experts agree, is by accident.  That’s where we come in; we’re computer professionals.  We cause accidents.”— Nathaniel Borenstein    28 | “Pessimists, we’re told, look at a glass containing 50% air and 50% water and see it as half empty.  Optimists, in contrast, see it as half full.  Engineers, of course, understand the glass is twice as big as it needs to be.”— Bob Lewis    29 | “In a room full of top software designers, if two agree on the same thing, that’s a majority.”— Bill Curtis    30 | “It should be noted that no ethically-trained software engineer would ever consent to write a DestroyBaghdad procedure.  Basic professional ethics would instead require him to write a DestroyCity procedure, to which Baghdad could be given as a parameter.”— Nathaniel S. Borenstein    31 | “Mostly, when you see programmers, they aren’t doing anything.  One of the attractive things about programmers is that you cannot tell whether or not they are working simply by looking at them.  Very often they’re sitting there seemingly drinking coffee and gossiping, or just staring into space.  What the programmer is trying to do is get a handle on all the individual and unrelated ideas that are scampering around in his head.”— Charles M. Strauss    32 | “If you think you are worth what you know, you are very wrong.  Your knowledge today does not have much value beyond a couple of years.  Your value is what you can learn and how easily you can adapt to the changes this profession brings so often.”— Jose M. Aguilar    33 | “Programs must be written for people to read, and only incidentally for machines to execute.”— Abelson and Sussman    34 | “Commenting your code is like cleaning your bathroom — you never want to do it, but it really does create a more pleasant experience for you and your guests.”— Ryan Campbell   35 | “We have to stop optimizing for programmers and start optimizing for users.”— Jeff Atwood    36 | “Low-level programming is good for the programmer’s soul.”— John Carmack    37 | “It’s OK to figure out murder mysteries, but you shouldn’t need to figure out code.  You should be able to read it.”— Steve McConnell    38 | “If we wish to count lines of code, we should not regard them as ‘lines produced’ but as ‘lines spent.'”— Edsger Dijkstra    39 | “Programming can be fun, so can cryptography; however they should not be combined.”— Kreitzberg and Shneiderman   40 | “Before software should be reusable, it should be usable.”— Ralph Johnson   41 | “If you automate a mess, you get an automated mess.”— Rod Michael    42 | “Looking at code you wrote more than two weeks ago is like looking at code you are seeing for the first time.”— Dan Hurvitz    43 | “It is easier to change the specification to fit the program than vice versa.”— Alan Perlis    44 | “Less than 10% of the code has to do with the ostensible purpose of the system; the rest deals with input-output, data validation, data structure maintenance, and other housekeeping.”— Mary Shaw    45 | “If you have a procedure with ten parameters, you probably missed some.”— Alan Perlis   46 | “How rare it is that maintaining someone else’s code is akin to entering a beautifully designed building, which you admire as you walk around and plan how to add a wing or do some redecorating. More often, maintaining someone else’s code is like being thrown headlong into a big pile of slimy, smelly garbage.”— Bill Venners    47 | “Code generation, like drinking alcohol, is good in moderation.”— Alex Lowe   48 | “Simplicity, carried to the extreme, becomes elegance.”— Jon Franklin    49 | “A program is never less than 90% complete, and never more than 95% complete.”— Terry Baker    50 | “When you are stuck in a traffic jam with a Porsche, all you do is burn more gas in idle.  Scalability is about building wider roads, not about building faster cars.”— Steve Swartz    51 | “Everyone by now presumably knows about the danger of premature optimization.  I think we should be just as worried about premature design — designing too early what a program should do.”— Paul Graham    52 | “Programming without an overall architecture or design in mind is like exploring a cave with only a flashlight: You don’t know where you’ve been, you don’t know where you’re going, and you don’t know quite where you are.”— Danny Thorpe    53 | “The best way to predict the future is to implement it.”— David Heinemeier Hansson    54 | “We need above all to know about changes; no one wants or needs to be reminded 16 hours a day that his shoes are on.”— David Hubel    55 | “On two occasions I have been asked, ‘If you put into the machine wrong figures, will the right answers come out?’  I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question.”— Charles Babbage   56 | “Make everything as simple as possible, but not simpler.”— Albert Einstein    57 | “Today, most software exists, not to solve a problem, but to interface with other software.”— IO Angell    58 | “Good specifications will always improve programmer productivity far better than any programming tool or technique.”— Milt Bryce    59 | “The difference between theory and practice is that in theory, there is no difference between theory and practice.”— Richard Moore    60 | “Don’t document the problem, fix it.”— Atli Björgvin Oddsson    61 | “As a rule, software systems do not work well until they have been used, and have failed repeatedly, in real applications.”— Dave Parnas    62 | “If the code and the comments do not match, possibly both are incorrect.”— Norm Schryer    63 | “I think it’s a new feature.  Don’t tell anyone it was an accident.”— Larry Wall    64 | “If you don’t handle [exceptions], we shut your application down.  That dramatically increases the reliability of the system.”— Anders Hejlsberg    65 | “When debugging, novices insert corrective code; experts remove defective code.”— Richard Pattis    66 | “In a software project team of 10, there are probably 3 people who produce enough defects to make them net negative producers.”— Gordon Schulmeyer    67 | “I think it is inevitable that people program poorly.  Training will not substantially help matters.  We have to learn to live with it.”— Alan Perlis    68 | “Program testing can be a very effective way to show the presence of bugs, but is hopelessly inadequate for showing their absence.”— Edsger Dijkstra    69 | “Manually managing blocks of memory in C is like juggling bars of soap in a prison shower: It’s all fun and games until you forget about one of them.”— anonymous Usenet user    70 | “There’s no obfuscated Perl contest because it’s pointless.”— Jeff Polk    71 | “Java is the most distressing thing to hit computing since MS-DOS.”— Alan Kay   72 | “There are only two things wrong with C++:  The initial concept and the implementation.”— Bertrand Meyer    73 | “It was a joke, okay?  If we thought it would actually be used, we wouldn’t have written it!”— Mark Andreesen, speaking of the HTML tag BLINK       74 | “Perl: The only language that looks the same before and after RSA encryption.”— Keith Bostic    75 | “I didn’t work hard to make Ruby perfect for everyone, because you feel differently from me.  No language can be perfect for everyone.  I tried to make Ruby perfect for me, but maybe it’s not perfect for you.  The perfect language for Guido van Rossum is probably Python.”— Yukihiro Matsumoto, aka “Matz”, creator of Ruby    76 | “XML is not a language in the sense of a programming language any more than sketches on a napkin are a language.”— Charles Simonyi    77 | “BASIC is to computer programming as QWERTY is to typing.”— Seymour Papert    78 | “It has been discovered that C++ provides a remarkable facility for concealing the trivial details of a program — such as where its bugs are.”— David Keppel    79 | “UNIX is simple.  It just takes a genius to understand its simplicity.”— Dennis Ritchie    80 | “Some people, when confronted with a problem, think ‘I know, I’ll use regular expressions.’  Now they have two problems.”— Jamie Zawinski    81 | “I think computer viruses should count as life.  I think it says something about human nature that the only form of life we have created so far is purely destructive.  We’ve created life in our own image.”— Stephen Hawking    82 | “The only truly secure system is one that is powered off, cast in a block of concrete and sealed in a lead-lined room with armed guards.”— Gene Spafford    83 | “Being able to break security doesn’t make you a hacker anymore than being able to hotwire cars makes you an automotive engineer.”— Eric Raymond    84 | “Companies spend millions of dollars on firewalls, encryption and secure access devices, and it’s money wasted, because none of these measures address the weakest link in the security chain.”— Kevin Mitnick    85 | “If you think technology can solve your security problems, then you don’t understand the problems and you don’t understand the technology.”— Bruce Schneier   86 | “Hoaxes use weaknesses in human behavior to ensure they are replicated and distributed.  In other words, hoaxes prey on the Human Operating System.”— Stewart Kirkpatrick    87 | “Passwords are like underwear: you don’t let people see it, you should change it very often, and you shouldn’t share it with strangers.”— Chris Pirillo   88 | “I am not out to destroy Microsoft, that would be a completely unintended side effect.”— Linus Torvalds    89 | “Yes, we have a dress code. You have to dress.”— Scott McNealy, co-founder of Sun Microsystems    90 | “In an information economy, the most valuable company assets drive themselves home every night.  If they are not treated well, they do not return the next morning.”— Peter Chang   91 | “It’s better to wait for a productive programmer to become available than it is to wait for the first available programmer to become productive.”— Steve McConnell 92 | “I’m not one of those who think Bill Gates is the devil.  I simply suspect that if Microsoft ever met up with the devil, it wouldn’t need an interpreter.”— Nicholas Petreley    93 | “Two years from now, spam will be solved.”— Bill Gates, 2004    94 | “The problem of viruses is temporary and will be solved in two years.”— John McAfee, 1988   95 | “Computer viruses are an urban legend.”— Peter Norton, 1988    96 | “In 2031, lawyers will be commonly a part of most development teams.”— Grady Booch    97 | “I don’t know what the language of the year 2000 will look like, but I know it will be called Fortran.”— CA Hoare, 1982   98 | “In the future, computers may weigh no more than 1.5 tonnes.”— Popular mechanics, 1949    99 | “I see little commercial potential for the Internet for at least ten years.”— Bill Gates, 1994    100 | “Before man reaches the moon, mail will be delivered within hours from New York to California, to Britain, to India or Australia.”— Arthur Summerfield, 1959, United States Post 101 | “The world is one big data problem.”— Andrew McAfee 102 | “Data levels all arguments.”— Anthony W. Richardson 103 | “Maybe stories are just data with a soul.”— Brené Brown 104 | “The data speaks for itself. That’s the easiest measure of success.”— Caitlin Smallwood 105 | “The goal is to turn data into information, and information into insight.”— Carly Fiorina 106 | “The best way to learn data science is to do data science.”— Chanin Nantasenamat 107 | “The great thing about predictions is that you can be wrong.”— Chris Wiggins 108 | “In Data Science if you want to help individuals, be empathetic and ask questions; that way, you can begin to understand their journey, too.”— Damian Duffy Mingle 109 | “As data scientists, our job is to extract signal from noise.”— Daniel Tunkelang 110 | “Without a systematic way to start and keep data clean, bad data will happen.”— Donato Diorio 111 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | PyGithub==1.51 2 | requests==2.24.0 3 | beautifulsoup4==4.9.3 -------------------------------------------------------------------------------- /scripts/scrape_fun_facts.py: -------------------------------------------------------------------------------- 1 | #./scripts/scrap_fun_facts.py 2 | """ 3 | Python Script to scrap amazing fun facts. 4 | """ 5 | 6 | import os 7 | import re 8 | from typing import List 9 | from urllib.request import Request, urlopen 10 | from bs4 import BeautifulSoup 11 | from bs4.element import Tag 12 | 13 | QUOTES_FILENAME = "/funfacts.txt" 14 | QUOTES_TXT_PATH = os.getcwd() + "/funfacts" 15 | QUOTES_FILE_PATH = QUOTES_TXT_PATH + QUOTES_FILENAME 16 | QUOTES_URL = "https://gotechug.com/interesting-facts-about-computers-you-didnt-know/" 17 | 18 | def get_bs4_obj(url: str) -> BeautifulSoup: 19 | ''' 20 | Get BeautifulSoup object for given QOUTES_URL. 21 | ''' 22 | # See reason to use Request: https://stackoverflow.com/questions/16627227/http-error-403-in-python-3-web-scraping 23 | req = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) 24 | html = urlopen(req).read() 25 | bs4Obj = BeautifulSoup(html, 'html.parser') 26 | return bs4Obj 27 | 28 | def filter_p_tags(ptag: Tag) -> bool: 29 | ''' 30 | Get required p tags only. 31 | ''' 32 | return re.match(r"[0-9]+.", ptag.get_text()) 33 | 34 | def get_p_tags(bs4Obj: BeautifulSoup) -> List[Tag]: 35 | ''' 36 | Get all p tags from the BeautifulSoup obj. 37 | 38 | Note: It is the requirement for given QUOTES_URL, it shall be different for different URL to scrap. 39 | ''' 40 | allP = bs4Obj.find_all('p') 41 | allReleventP = list(filter(filter_p_tags, allP)) 42 | return allReleventP 43 | 44 | def get_all_facts(ptags: List[Tag]): 45 | ''' 46 | Yield all facts present in p tags. 47 | ''' 48 | for p in ptags: 49 | fact = re.sub(r"[0-9]+\. ", "", p.get_text()) 50 | yield fact + "\n" 51 | 52 | def save_fun_facts(ptags: List[Tag]): 53 | ''' 54 | Save extracted qoutes in a text file, create a new folder if not already present 55 | ''' 56 | global QUOTES_TXT_PATH, QUOTES_FILE_PATH 57 | if not os.path.exists(QUOTES_TXT_PATH): 58 | os.mkdir(QUOTES_TXT_PATH) 59 | 60 | with open(QUOTES_FILE_PATH, 'w') as file: 61 | for txt in get_all_facts(ptags): 62 | file.write(txt) 63 | 64 | print(f'All Fun Facts written to file: {QUOTES_FILE_PATH}') 65 | 66 | 67 | if __name__ == "__main__": 68 | bs4Obj = get_bs4_obj(QUOTES_URL) 69 | allP = get_p_tags(bs4Obj) 70 | save_fun_facts(allP) -------------------------------------------------------------------------------- /scripts/scrape_quotes.py: -------------------------------------------------------------------------------- 1 | #./scripts/scrap_quotes.py 2 | """ 3 | Python Script to scrap amazing quotes by some great computer scientists 4 | """ 5 | 6 | import os 7 | from typing import List 8 | from urllib.request import Request, urlopen 9 | from bs4 import BeautifulSoup 10 | from bs4.element import Tag 11 | 12 | QUOTES_FILENAME = "/quotes.txt" 13 | QUOTES_TXT_PATH = os.getcwd() + "/quotes" 14 | QUOTES_FILE_PATH = QUOTES_TXT_PATH + QUOTES_FILENAME 15 | QUOTES_URL = "http://www.devtopics.com/101-more-great-computer-quotes/" 16 | 17 | def get_bs4_obj(url: str) -> BeautifulSoup: 18 | ''' 19 | Get BeautifulSoup object for given QOUTES_URL. 20 | ''' 21 | # See reason to use Request: https://stackoverflow.com/questions/16627227/http-error-403-in-python-3-web-scraping 22 | req = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) 23 | html = urlopen(req).read() 24 | bs4Obj = BeautifulSoup(html, 'html.parser') 25 | return bs4Obj 26 | 27 | 28 | def get_ol_tags(bs4Obj: BeautifulSoup) -> List[Tag]: 29 | ''' 30 | Get all ol tags from the bs4 obj. 31 | 32 | Note: It is the requirement for given QUOTES_URL, it shall be different for different URL to scrap. 33 | ''' 34 | allOL = bs4Obj.find_all('ol') 35 | allReleventOL = list(filter(lambda ol: ol.attrs.get('class')!=['commentlist'], allOL)) 36 | return allReleventOL 37 | 38 | 39 | def get_all_quotes(oltags: List[Tag]): 40 | ''' 41 | Yield all qoutes present in OL tags. 42 | ''' 43 | for ol in oltags: 44 | yield ol.find('li').get_text() 45 | 46 | 47 | def save_qoutes(oltags: List[Tag]): 48 | ''' 49 | Save extracted qoutes in a text file, create a new folder if not already present 50 | ''' 51 | global QUOTES_TXT_PATH, QUOTES_FILE_PATH 52 | if not os.path.exists(QUOTES_TXT_PATH): 53 | os.mkdir(QUOTES_TXT_PATH) 54 | 55 | with open(QUOTES_FILE_PATH, 'w') as file: 56 | for txt in get_all_quotes(oltags): 57 | file.write(txt) 58 | 59 | print(f'All Quotes written to file: {QUOTES_FILE_PATH}') 60 | 61 | 62 | if __name__ == "__main__": 63 | bs4Obj = get_bs4_obj(QUOTES_URL) 64 | olTags = get_ol_tags(bs4Obj) 65 | save_qoutes(olTags) -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siddharth2016/quote-readme/a0d04b5b5863ae4a82e07de7a8aa0e3b0367fc51/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_main.py: -------------------------------------------------------------------------------- 1 | #tests/test_main.py 2 | """ 3 | Tests for main.py 4 | """ 5 | 6 | from main import get_option_list, get_text_to_display 7 | import unittest 8 | from unittest.mock import patch, Mock 9 | 10 | class TestQuoteReadme(unittest.TestCase): 11 | 12 | def test_get_option_list(self): 13 | with patch('main.get_quotes') as mockquotes: 14 | with patch('main.get_funfacts') as mockfacts: 15 | with patch('main.random.shuffle') as mockshuffle: 16 | mockquotes.return_value = ['quote1', 'quote2'] 17 | actual = get_option_list('quote') 18 | self.assertEqual(['quote1', 'quote2'], actual) 19 | 20 | mockfacts.return_value = ['fact1', 'fact2'] 21 | actual = get_option_list('funfact') 22 | self.assertEqual(['fact1', 'fact2'], actual) 23 | 24 | mockshuffle.return_value = ['quote1', 'quote2', 'fact1', 'fact2'] 25 | actual = get_option_list('both') 26 | self.assertEqual(['quote1', 'quote2', 'fact1', 'fact2'], actual) 27 | 28 | def test_get_text_to_display(self): 29 | with patch('main.get_option_list') as mockoptionlist: 30 | with patch('main.get_quote_funfact') as mockquote: 31 | mockquote.return_value = 'mock quote.\n' 32 | actual = get_text_to_display() 33 | self.assertEqual('❝mock quote.❞', actual) 34 | 35 | mockquote.return_value = '\xa0mock quote.\n' 36 | actual = get_text_to_display() 37 | self.assertEqual('❝ mock quote.❞', actual) 38 | 39 | 40 | 41 | 42 | if __name__ == "__main__": 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /tests/test_scrape_funfacts.py: -------------------------------------------------------------------------------- 1 | #tests/test_scrap_funfacts.py 2 | """ 3 | Test for scarp_funfacts.py 4 | """ 5 | 6 | from scripts.scrape_fun_facts import get_bs4_obj, get_p_tags, get_all_facts, filter_p_tags 7 | import unittest 8 | from unittest.mock import patch, Mock 9 | from bs4 import BeautifulSoup 10 | import re 11 | 12 | class TestScrapFunFacts(unittest.TestCase): 13 | 14 | def setUp(self): 15 | 16 | self.html = """ 17 | 18 | 19 | 20 |

66. some text

21 | 22 | 23 | """ 24 | self.dummyurl = 'someurl.com' 25 | 26 | def test_get_bs4_obj(self): 27 | with patch('scripts.scrape_fun_facts.Request') as mockreq: 28 | with patch('scripts.scrape_fun_facts.urlopen') as mockurlopen: 29 | mockurlopen.return_value.read.return_value = self.html 30 | actual = get_bs4_obj(self.dummyurl) 31 | expected = BeautifulSoup(self.html, 'html.parser') 32 | self.assertEqual(expected, actual) 33 | 34 | def test_get_p_tags(self): 35 | bs4Obj = BeautifulSoup(self.html, 'html.parser') 36 | actual = get_p_tags(bs4Obj) 37 | expected = bs4Obj.find_all('p') 38 | self.assertEqual(expected, actual) 39 | 40 | def test_get_all_facts(self): 41 | bs4Obj = BeautifulSoup(self.html, 'html.parser') 42 | allp = bs4Obj.find_all('p') 43 | actual = list(get_all_facts(allp)) 44 | self.assertEqual(['some text\n'], actual) 45 | 46 | def test_filter_p_tags(self): 47 | bs4Obj = BeautifulSoup(self.html, 'html.parser') 48 | allp = bs4Obj.find_all('p') 49 | actual = filter_p_tags(allp[0]) 50 | expected = re.match(r"[0-9]+.", allp[0].get_text()) 51 | self.assertEqual(str(expected), str(actual)) 52 | 53 | 54 | if __name__ == "__main__": 55 | unittest.main() 56 | -------------------------------------------------------------------------------- /tests/test_scrape_quotes.py: -------------------------------------------------------------------------------- 1 | #tests/test_scrap_quotes.py 2 | """ 3 | Test for scrap_quotes.py 4 | """ 5 | 6 | from scripts.scrape_quotes import get_bs4_obj, get_ol_tags, get_all_quotes 7 | import unittest 8 | from unittest.mock import patch, Mock 9 | from bs4 import BeautifulSoup 10 | 11 | class TestScrapQuotes(unittest.TestCase): 12 | 13 | def setUp(self): 14 | 15 | self.html = """ 16 | 17 | 18 | 19 |
    20 |
  1. some text
  2. 21 |
22 | 23 | 24 | """ 25 | self.dummyurl = 'someurl.com' 26 | 27 | def test_get_bs4_obj(self): 28 | with patch('scripts.scrape_quotes.Request') as mockreq: 29 | with patch('scripts.scrape_quotes.urlopen') as mockurlopen: 30 | mockurlopen.return_value.read.return_value = self.html 31 | actual = get_bs4_obj(self.dummyurl) 32 | expected = BeautifulSoup(self.html, 'html.parser') 33 | self.assertEqual(expected, actual) 34 | 35 | def test_get_ol_tags(self): 36 | bs4Obj = BeautifulSoup(self.html, 'html.parser') 37 | actual = get_ol_tags(bs4Obj) 38 | expected = bs4Obj.find_all('ol') 39 | self.assertEqual(expected, actual) 40 | 41 | def test_get_all_quotes(self): 42 | bs4Obj = BeautifulSoup(self.html, 'html.parser') 43 | ollist = bs4Obj.find_all('ol') 44 | actual = list(get_all_quotes(ollist)) 45 | self.assertEqual(['some text'], actual) 46 | 47 | 48 | if __name__ == "__main__": 49 | unittest.main() 50 | --------------------------------------------------------------------------------