mirror of
https://github.com/satwikkansal/wtfpython
synced 2024-11-24 03:54:25 +01:00
Merge branch 'master' into patch-1
This commit is contained in:
commit
2cd029f87c
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
wtfpython-pypi/build/
|
wtfpython-pypi/build/
|
||||||
@ -8,3 +10,9 @@ wtfpython-pypi/wtfpython.egg-info
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
|
||||||
|
irrelevant/.ipynb_checkpoints/
|
||||||
|
|
||||||
|
irrelevant/.python-version
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
1
.npmignore
vendored
1
.npmignore
vendored
@ -1 +0,0 @@
|
|||||||
irrelevant/
|
|
3
.travis.yml
vendored
Normal file
3
.travis.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
language: python
|
||||||
|
install: pip install flake8
|
||||||
|
script: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
11
CONTRIBUTING.md
vendored
11
CONTRIBUTING.md
vendored
@ -1,6 +1,6 @@
|
|||||||
All kinds of patches are welcome. Feel free to even suggest some catchy and funny titles for the existing Examples. The goal is to make this collection as interesting to read as possible.
|
All kinds of patches are welcome. Feel free to even suggest some catchy and funny titles for the existing Examples. The goal is to make this collection as interesting to read as possible.
|
||||||
|
|
||||||
If you are interested in translating the project to another language (some people have done that in the past), please feel free to open up an issue or ping on the [gitter channel](https://gitter.im/wtfpython/Lobby) if you need any kind of help.
|
If you are interested in translating the project to another language (some people have done that in the past), please feel free to open up an issue, and let me know if you need any kind of help.
|
||||||
|
|
||||||
If the changes you suggest are significant, filing an issue before submitting the actual patch will be appreciated. If you'd like to work on the issue (highly encouraged), you can mention that you're interested in working on it while creating the issue and get assigned to it.
|
If the changes you suggest are significant, filing an issue before submitting the actual patch will be appreciated. If you'd like to work on the issue (highly encouraged), you can mention that you're interested in working on it while creating the issue and get assigned to it.
|
||||||
|
|
||||||
@ -29,10 +29,17 @@ Probably unexpected output
|
|||||||
```py
|
```py
|
||||||
Setting up examples for clarification (if necessary)
|
Setting up examples for clarification (if necessary)
|
||||||
```
|
```
|
||||||
**Outupt:**
|
**Output:**
|
||||||
```py
|
```py
|
||||||
>>> trigger # some example that makes it easy to unveil the magic
|
>>> trigger # some example that makes it easy to unveil the magic
|
||||||
# some justified output
|
# some justified output
|
||||||
```
|
```
|
||||||
```
|
```
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
Few things that you can consider while writing an example,
|
||||||
|
|
||||||
|
- Try to be consistent with the namings and the values you use with the variables. For instance, most variable names in the project are along the lines of `some_string`, `some_list`, `some_dict`, etc. You'd see a lot of `x`s for single letter variable names, and `"wtf"` as values for strings. There's strictly enforced scheme in the project, but you can take a glance at other examples to get a gist.
|
||||||
|
- Try to be as creative as possible to add that element of "surprise" in the setting up part of an example. Sometimes this may mean writing a snippet a sane programmer would never write.
|
||||||
|
- Also, please don't forget to add your name to the [contributors list](/CONTRIBUTING.md).
|
||||||
|
34
CONTRIBUTORS.md
vendored
34
CONTRIBUTORS.md
vendored
@ -1,14 +1,28 @@
|
|||||||
I'm really grateful to all the contributors. Following are the wonderful people (in no specific order) who have contributed their examples to wtfpython.
|
Following are the wonderful people (in no specific order) who have contributed their examples to wtfpython.
|
||||||
|
|
||||||
| Contributor | Github | Issues |
|
| Contributor | Github | Issues |
|
||||||
|-------------|--------|--------|
|
|-------------|--------|--------|
|
||||||
| Lucas-C | [Lucas-C](https://github.com/Lucas-C) | [#36](https:/github.com/satwikkansal/wtfpython/issues/36) |
|
| Lucas-C | [Lucas-C](https://github.com/Lucas-C) | [#36](https://github.com/satwikkansal/wtfpython/issues/36) |
|
||||||
| MittalAshok | [MittalAshok](https://github.com/MittalAshok) | [#23](https:/github.com/satwikkansal/wtfpython/issues/23) |
|
| MittalAshok | [MittalAshok](https://github.com/MittalAshok) | [#23](https://github.com/satwikkansal/wtfpython/issues/23) |
|
||||||
| asottile | [asottile](https://github.com/asottile) | [#40](https:/github.com/satwikkansal/wtfpython/issues/40) |
|
| asottile | [asottile](https://github.com/asottile) | [#40](https://github.com/satwikkansal/wtfpython/issues/40) |
|
||||||
| MostAwesomeDude | [MostAwesomeDude](https://github.com/MostAwesomeDude) | [#1](https:/github.com/satwikkansal/wtfpython/issues/1) |
|
| MostAwesomeDude | [MostAwesomeDude](https://github.com/MostAwesomeDude) | [#1](https://github.com/satwikkansal/wtfpython/issues/1) |
|
||||||
| tukkek | [tukkek](https://github.com/tukkek) | [#11](https:/github.com/satwikkansal/wtfpython/issues/11), [#26](https:/github.com/satwikkansal/wtfpython/issues/26) |
|
| tukkek | [tukkek](https://github.com/tukkek) | [#11](https://github.com/satwikkansal/wtfpython/issues/11), [#26](https://github.com/satwikkansal/wtfpython/issues/26) |
|
||||||
| PiaFraus | [PiaFraus](https://github.com/PiaFraus) | [#9](https:/github.com/satwikkansal/wtfpython/issues/9) |
|
| PiaFraus | [PiaFraus](https://github.com/PiaFraus) | [#9](https://github.com/satwikkansal/wtfpython/issues/9) |
|
||||||
| chris-rands | [chris-rands](https://github.com/chris-rands) | [#32](https:/github.com/satwikkansal/wtfpython/issues/32) |
|
| chris-rands | [chris-rands](https://github.com/chris-rands) | [#32](https://github.com/satwikkansal/wtfpython/issues/32) |
|
||||||
| sohaibfarooqi | [sohaibfarooqi](https://github.com/sohaibfarooqi) | [#63](https:/github.com/satwikkansal/wtfpython/issues/63) |
|
| sohaibfarooqi | [sohaibfarooqi](https://github.com/sohaibfarooqi) | [#63](https://github.com/satwikkansal/wtfpython/issues/63) |
|
||||||
|
| ipid | [ipid](https://github.com/ipid) | [#145](https://github.com/satwikkansal/wtfpython/issues/145) |
|
||||||
|
| roshnet | [roshnet](https://github.com/roshnet) | [#140](https://github.com/satwikkansal/wtfpython/issues/140) |
|
||||||
|
| daidai21 | [daidai21](https://github.com/daidai21) | [#137](https://github.com/satwikkansal/wtfpython/issues/137) |
|
||||||
|
| scidam | [scidam](https://github.com/scidam) | [#136](https://github.com/satwikkansal/wtfpython/issues/136) |
|
||||||
|
| pmjpawelec | [pmjpawelec](https://github.com/pmjpawelec) | [#121](https://github.com/satwikkansal/wtfpython/issues/121) |
|
||||||
|
| leisurelicht | [leisurelicht](https://github.com/leisurelicht) | [#112](https://github.com/satwikkansal/wtfpython/issues/112) |
|
||||||
|
| mishaturnbull | [mishaturnbull](https://github.com/mishaturnbull) | [#108](https://github.com/satwikkansal/wtfpython/issues/108) |
|
||||||
|
| MuseBoy | [MuseBoy](https://github.com/MuseBoy) | [#101](https://github.com/satwikkansal/wtfpython/issues/101) |
|
||||||
|
| Ghost account | N/A | [#96](https://github.com/satwikkansal/wtfpython/issues/96)
|
||||||
|
| koddo | [koddo](https://github.com/koddo) | [#80](https://github.com/satwikkansal/wtfpython/issues/80), [#73](https://github.com/satwikkansal/wtfpython/issues/73) |
|
||||||
|
| jab | [jab](https://github.com/jab) | [#77](https://github.com/satwikkansal/wtfpython/issues/77) |
|
||||||
|
|
||||||
Thank you all for taking out time, and helping to make this project awesome! :smile:
|
|
||||||
|
Thank you all for your time and making wtfpython more awesome! :smile:
|
||||||
|
|
||||||
|
PS: This list is updated after every major release, if I forgot to add your contribution here, please feel free to raise a Pull request.
|
||||||
|
0
irrelevant/generated.md
vendored
0
irrelevant/generated.md
vendored
24
irrelevant/insert_ids.py
Normal file
24
irrelevant/insert_ids.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import uuid
|
||||||
|
|
||||||
|
new_file = []
|
||||||
|
original_file = []
|
||||||
|
|
||||||
|
fname = "../README.md"
|
||||||
|
|
||||||
|
|
||||||
|
def generate_random_id_comment():
|
||||||
|
random_id = uuid.uuid4()
|
||||||
|
return f"<!-- Example ID: {random_id} --!>"
|
||||||
|
|
||||||
|
|
||||||
|
with open(fname, "r") as f:
|
||||||
|
original_file = f.readlines()
|
||||||
|
|
||||||
|
|
||||||
|
for line in original_file:
|
||||||
|
new_file.append(line)
|
||||||
|
if line.strip().startswith("### "):
|
||||||
|
new_file.append(generate_random_id_comment())
|
||||||
|
|
||||||
|
with open(fname, "w") as f:
|
||||||
|
f.write("".join(new_file))
|
354
irrelevant/notebook_generator.py
Normal file
354
irrelevant/notebook_generator.py
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
"""
|
||||||
|
An inefficient monolithic piece of code that'll generate jupyter notebook
|
||||||
|
from the projects main README.
|
||||||
|
|
||||||
|
PS: If you are a recruiter, please don't judge me by this piece of code. I wrote it
|
||||||
|
in hurry. I know this is messy and can be simplified, but I don't want to change it
|
||||||
|
much because it just works.
|
||||||
|
|
||||||
|
Simplifictions and improvements through patches are more than welcome however :)
|
||||||
|
|
||||||
|
|
||||||
|
#TODOs
|
||||||
|
|
||||||
|
- CLI arguments for running this thing
|
||||||
|
- Add it to prepush hook
|
||||||
|
- Add support for skip comments, to skip examples that are not meant for notebook environment.
|
||||||
|
- Use templates?
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
fpath = os.path.join(os.path.dirname( __file__ ), '..', 'README.md')
|
||||||
|
examples = []
|
||||||
|
|
||||||
|
# The globals
|
||||||
|
current_example = 1
|
||||||
|
sequence_num = 1
|
||||||
|
current_section_name = ""
|
||||||
|
|
||||||
|
|
||||||
|
STATEMENT_PREFIXES = ["...", ">>> ", "$ "]
|
||||||
|
|
||||||
|
HOSTED_NOTEBOOK_INSTRUCTIONS = """
|
||||||
|
|
||||||
|
## Hosted notebook instructions
|
||||||
|
|
||||||
|
This is just an experimental attempt of browsing wtfpython through jupyter notebooks. Some examples are read-only because,
|
||||||
|
- they either require a version of Python that's not supported in the hosted runtime.
|
||||||
|
- or they can't be reproduced in the notebook envrinonment.
|
||||||
|
|
||||||
|
The expected outputs are already present in collapsed cells following the code cells. The Google colab provides Python2 (2.7) and Python3 (3.6, default) runtimes. You can switch among these for Python2 specific examples. For examples specific to other minor versions, you can simply refer to collapsed outputs (it's not possible to control the minor version in hosted notebooks as of now). You can check the active version using
|
||||||
|
|
||||||
|
```py
|
||||||
|
>>> import sys
|
||||||
|
>>> sys.version
|
||||||
|
# Prints out Python version here.
|
||||||
|
```
|
||||||
|
|
||||||
|
That being said, most of the examples do work as expected. If you face any trouble, feel free to consult the original content on wtfpython and create an issue in the repo. Have fun!
|
||||||
|
|
||||||
|
---
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def generate_code_block(statements, output):
|
||||||
|
global sequence_num
|
||||||
|
result = {
|
||||||
|
"type": "code",
|
||||||
|
"sequence_num": sequence_num,
|
||||||
|
"statements": statements,
|
||||||
|
"output": output
|
||||||
|
}
|
||||||
|
sequence_num += 1
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def generate_markdown_block(lines):
|
||||||
|
global sequence_num
|
||||||
|
result = {
|
||||||
|
"type": "markdown",
|
||||||
|
"sequence_num": sequence_num,
|
||||||
|
"value": lines
|
||||||
|
}
|
||||||
|
sequence_num += 1
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def is_interactive_statement(line):
|
||||||
|
for prefix in STATEMENT_PREFIXES:
|
||||||
|
if line.lstrip().startswith(prefix):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def parse_example_parts(lines, title, current_line):
|
||||||
|
parts = {
|
||||||
|
"build_up": [],
|
||||||
|
"explanation": []
|
||||||
|
}
|
||||||
|
content = [title]
|
||||||
|
statements_so_far = []
|
||||||
|
output_so_far = []
|
||||||
|
next_line = current_line
|
||||||
|
# store build_up till an H4 (explanation) is encountered
|
||||||
|
while not (next_line.startswith("#### ")or next_line.startswith('---')):
|
||||||
|
# Watching out for the snippets
|
||||||
|
if next_line.startswith("```py"):
|
||||||
|
# It's a snippet, whatever found until now is text
|
||||||
|
is_interactive = False
|
||||||
|
output_encountered = False
|
||||||
|
if content:
|
||||||
|
parts["build_up"].append(generate_markdown_block(content))
|
||||||
|
content = []
|
||||||
|
|
||||||
|
next_line = next(lines)
|
||||||
|
|
||||||
|
while not next_line.startswith("```"):
|
||||||
|
if is_interactive_statement(next_line):
|
||||||
|
is_interactive = True
|
||||||
|
if (output_so_far):
|
||||||
|
parts["build_up"].append(generate_code_block(statements_so_far, output_so_far))
|
||||||
|
statements_so_far, output_so_far = [], []
|
||||||
|
statements_so_far.append(next_line)
|
||||||
|
else:
|
||||||
|
# can be either output or normal code
|
||||||
|
if is_interactive:
|
||||||
|
output_so_far.append(next_line)
|
||||||
|
elif output_encountered:
|
||||||
|
output_so_far.append(next_line)
|
||||||
|
else:
|
||||||
|
statements_so_far.append(next_line)
|
||||||
|
next_line = next(lines)
|
||||||
|
|
||||||
|
# Snippet is over
|
||||||
|
parts["build_up"].append(generate_code_block(statements_so_far, output_so_far))
|
||||||
|
statements_so_far, output_so_far = [], []
|
||||||
|
next_line = next(lines)
|
||||||
|
else:
|
||||||
|
# It's a text, go on.
|
||||||
|
content.append(next_line)
|
||||||
|
next_line = next(lines)
|
||||||
|
|
||||||
|
# Explanation encountered, save any content till now (if any)
|
||||||
|
if content:
|
||||||
|
parts["build_up"].append(generate_markdown_block(content))
|
||||||
|
|
||||||
|
# Reset stuff
|
||||||
|
content = []
|
||||||
|
statements_so_far, output_so_far = [], []
|
||||||
|
|
||||||
|
# store lines again until --- or another H3 is encountered
|
||||||
|
while not (next_line.startswith("---") or
|
||||||
|
next_line.startswith("### ")):
|
||||||
|
if next_line.lstrip().startswith("```py"):
|
||||||
|
# It's a snippet, whatever found until now is text
|
||||||
|
is_interactive = False
|
||||||
|
if content:
|
||||||
|
parts["explanation"].append(generate_markdown_block(content))
|
||||||
|
content = []
|
||||||
|
|
||||||
|
next_line = next(lines)
|
||||||
|
|
||||||
|
while not next_line.lstrip().startswith("```"):
|
||||||
|
if is_interactive_statement(next_line):
|
||||||
|
is_interactive = True
|
||||||
|
if (output_so_far):
|
||||||
|
parts["explanation"].append(generate_code_block(statements_so_far, output_so_far))
|
||||||
|
statements_so_far, output_so_far = [], []
|
||||||
|
statements_so_far.append(next_line)
|
||||||
|
else:
|
||||||
|
# can be either output or normal code
|
||||||
|
if is_interactive:
|
||||||
|
output_so_far.append(next_line)
|
||||||
|
else:
|
||||||
|
statements_so_far.append(next_line)
|
||||||
|
next_line = next(lines)
|
||||||
|
|
||||||
|
# Snippet is over
|
||||||
|
parts["explanation"].append(generate_code_block(statements_so_far, output_so_far))
|
||||||
|
statements_so_far, output_so_far = [], []
|
||||||
|
next_line = next(lines)
|
||||||
|
else:
|
||||||
|
# It's a text, go on.
|
||||||
|
content.append(next_line)
|
||||||
|
next_line = next(lines)
|
||||||
|
|
||||||
|
# All done
|
||||||
|
if content:
|
||||||
|
parts["explanation"].append(generate_markdown_block(content))
|
||||||
|
|
||||||
|
return next_line, parts
|
||||||
|
|
||||||
|
|
||||||
|
def remove_from_beginning(tokens, line):
|
||||||
|
for token in tokens:
|
||||||
|
if line.lstrip().startswith(token):
|
||||||
|
line = line.replace(token, "")
|
||||||
|
return line
|
||||||
|
|
||||||
|
|
||||||
|
def inspect_and_sanitize_code_lines(lines):
|
||||||
|
tokens_to_remove = STATEMENT_PREFIXES
|
||||||
|
result = []
|
||||||
|
is_print_present = False
|
||||||
|
for line in lines:
|
||||||
|
line = remove_from_beginning(tokens_to_remove, line)
|
||||||
|
if line.startswith("print ") or line.startswith("print("):
|
||||||
|
is_print_present = True
|
||||||
|
result.append(line)
|
||||||
|
return is_print_present, result
|
||||||
|
|
||||||
|
|
||||||
|
def convert_to_cells(cell_contents, read_only):
|
||||||
|
cells = []
|
||||||
|
for stuff in cell_contents:
|
||||||
|
if stuff["type"] == "markdown":
|
||||||
|
# todo add metadata later
|
||||||
|
cells.append(
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": stuff["value"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
elif stuff["type"] == "code":
|
||||||
|
if read_only:
|
||||||
|
# Skip read only
|
||||||
|
# TODO: Fix
|
||||||
|
cells.append(
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": ["```py\n"] + stuff["statements"] + ["```\n"] + ["```py\n"] + stuff['output'] + ["```\n"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
is_print_present, sanitized_code = inspect_and_sanitize_code_lines(stuff["statements"])
|
||||||
|
if is_print_present:
|
||||||
|
cells.append(
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"metadata": {
|
||||||
|
"collapsed": True,
|
||||||
|
|
||||||
|
},
|
||||||
|
"execution_count": None,
|
||||||
|
"outputs": [{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": stuff["output"]
|
||||||
|
}],
|
||||||
|
"source": sanitized_code
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cells.append(
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": None,
|
||||||
|
"metadata": {
|
||||||
|
"collapsed": True
|
||||||
|
},
|
||||||
|
"outputs": [{
|
||||||
|
"data": {
|
||||||
|
"text/plain": stuff["output"]
|
||||||
|
},
|
||||||
|
"output_type": "execute_result",
|
||||||
|
"metadata": {},
|
||||||
|
"execution_count": None
|
||||||
|
}],
|
||||||
|
"source": sanitized_code
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return cells
|
||||||
|
|
||||||
|
|
||||||
|
def convert_to_notebook(pre_examples_content, parsed_json, post_examples_content):
|
||||||
|
result = {
|
||||||
|
"cells": [],
|
||||||
|
"metadata": {},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 2
|
||||||
|
}
|
||||||
|
|
||||||
|
notebook_path = "wtf.ipynb"
|
||||||
|
|
||||||
|
result["cells"] += convert_to_cells([generate_markdown_block(pre_examples_content)], False)
|
||||||
|
|
||||||
|
for example in parsed_json:
|
||||||
|
parts = example["parts"]
|
||||||
|
build_up = parts.get("build_up")
|
||||||
|
explanation = parts.get("explanation")
|
||||||
|
read_only = example.get("read_only")
|
||||||
|
|
||||||
|
if build_up:
|
||||||
|
result["cells"] += convert_to_cells(build_up, read_only)
|
||||||
|
|
||||||
|
if explanation:
|
||||||
|
result["cells"] += convert_to_cells(explanation, read_only)
|
||||||
|
|
||||||
|
result["cells"] += convert_to_cells([generate_markdown_block(post_examples_content)], False)
|
||||||
|
|
||||||
|
#pprint.pprint(result, indent=2)
|
||||||
|
with open(notebook_path, "w") as f:
|
||||||
|
json.dump(result, f, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
with open(fpath, 'r+', encoding="utf-8") as f:
|
||||||
|
lines = iter(f.readlines())
|
||||||
|
line = next(lines)
|
||||||
|
result = []
|
||||||
|
pre_examples_phase = True
|
||||||
|
pre_stuff = []
|
||||||
|
post_stuff = []
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
if line.startswith("## "):
|
||||||
|
pre_examples_phase = False
|
||||||
|
# A section is encountered
|
||||||
|
current_section_name = line.replace("## ", "").strip()
|
||||||
|
section_text = []
|
||||||
|
line = next(lines)
|
||||||
|
# Until a new section is encountered
|
||||||
|
while not (line.startswith("## ") or line.startswith("# ")):
|
||||||
|
# check if it's a H3
|
||||||
|
if line.startswith("### "):
|
||||||
|
# An example is encountered
|
||||||
|
title_line = line
|
||||||
|
line = next(lines)
|
||||||
|
read_only = False
|
||||||
|
while line.strip() == "" or line.startswith('<!--'):
|
||||||
|
#TODO: Capture example ID here using regex.
|
||||||
|
if '<!-- read-only -->' in line:
|
||||||
|
read_only = True
|
||||||
|
line = next(lines)
|
||||||
|
|
||||||
|
example_details = {
|
||||||
|
"id": current_example,
|
||||||
|
"title": title_line.replace("### ", ""),
|
||||||
|
"section": current_section_name,
|
||||||
|
"read_only": read_only
|
||||||
|
}
|
||||||
|
line, example_details["parts"] = parse_example_parts(lines, title_line, line)
|
||||||
|
result.append(example_details)
|
||||||
|
current_example += 1
|
||||||
|
else:
|
||||||
|
section_text.append(line)
|
||||||
|
line = next(lines)
|
||||||
|
else:
|
||||||
|
if pre_examples_phase:
|
||||||
|
pre_stuff.append(line)
|
||||||
|
else:
|
||||||
|
post_stuff.append(line)
|
||||||
|
line = next(lines)
|
||||||
|
|
||||||
|
except StopIteration as e:
|
||||||
|
#pprint.pprint(result, indent=2)
|
||||||
|
pre_stuff.append(HOSTED_NOTEBOOK_INSTRUCTIONS)
|
||||||
|
result.sort(key = lambda x: x["read_only"])
|
||||||
|
convert_to_notebook(pre_stuff, result, post_stuff)
|
7
irrelevant/notebook_instructions.md
vendored
Normal file
7
irrelevant/notebook_instructions.md
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
## Generating the notebook
|
||||||
|
|
||||||
|
- Expand the relative links in README.md to absolute ones
|
||||||
|
- Remove the TOC in README.md (because Google colab generates its own anyway)
|
||||||
|
- Reorder the examples, so that the ones that work are upfront.
|
||||||
|
- Run the `notebook_generator.py`, it will generate a notebook named `wtf.ipynb`
|
||||||
|
- Revert the README.md changes (optional)
|
@ -139,7 +139,7 @@ f*
|
|||||||
Half triple-quoted strings
|
Half triple-quoted strings
|
||||||
f
|
f
|
||||||
|
|
||||||
Implicity key type conversion
|
Implicit key type conversion
|
||||||
f*
|
f*
|
||||||
|
|
||||||
Stubborn `del` operator
|
Stubborn `del` operator
|
@ -1,6 +1,8 @@
|
|||||||
"""
|
"""
|
||||||
Parses the README.md and generated the table
|
This script parses the README.md and generates the table
|
||||||
`CONTRIBUTORS.md`.
|
`CONTRIBUTORS.md`.
|
||||||
|
|
||||||
|
No longer works since we've moved on contributors to CONTRIBUTORS.md entirely.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
@ -39,7 +41,7 @@ for handle, issues in contribs.items():
|
|||||||
issue_string = ', '.join([issue_format.format(i, i) for i in issues])
|
issue_string = ', '.join([issue_format.format(i, i) for i in issues])
|
||||||
resp = requests.get(github_rest_api.format(handle))
|
resp = requests.get(github_rest_api.format(handle))
|
||||||
name = handle
|
name = handle
|
||||||
if resp.status_code is 200:
|
if resp.status_code == 200:
|
||||||
pprint.pprint(resp.json()['name'])
|
pprint.pprint(resp.json()['name'])
|
||||||
else:
|
else:
|
||||||
print(handle, resp.content)
|
print(handle, resp.content)
|
12317
irrelevant/wtf.ipynb
vendored
Normal file
12317
irrelevant/wtf.ipynb
vendored
Normal file
File diff suppressed because it is too large
Load Diff
41
package.json
vendored
41
package.json
vendored
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "wtfpython",
|
|
||||||
"version": "2.1.0",
|
|
||||||
"description": "A collection of surprising Python snippets and lesser known features.",
|
|
||||||
"bin": "wtfpython",
|
|
||||||
"scripts": {
|
|
||||||
"postpublish": "git push origin master",
|
|
||||||
"toc": "doctoc --github --title '# Table of Contents' --maxlevel 3 README.md"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/satwikkansal/wtfPython.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"python",
|
|
||||||
"specification",
|
|
||||||
"notes",
|
|
||||||
"wtf",
|
|
||||||
"learning",
|
|
||||||
"guide",
|
|
||||||
"handbook"
|
|
||||||
],
|
|
||||||
"author": "Satwik Kansal <satwikkansal@gmail.com> (https://satwikkansal.xyz)",
|
|
||||||
"license": "WTFPL 2.0",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/satwikkansal/wtfPython/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/satwikkansal/wtfPython#readme",
|
|
||||||
"devDependencies": {
|
|
||||||
"doctoc": "^1.3.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"boxen": "^1.1.0",
|
|
||||||
"chalk": "^1.1.1",
|
|
||||||
"default-pager": "^1.1.0",
|
|
||||||
"meow": "^3.7.0",
|
|
||||||
"msee": "^0.3.3",
|
|
||||||
"through2": "^2.0.2",
|
|
||||||
"update-notifier": "^2.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
85
wtfpython
vendored
85
wtfpython
vendored
@ -1,85 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const obj = require('through2').obj;
|
|
||||||
const pager = require('default-pager');
|
|
||||||
const msee = require('msee');
|
|
||||||
const join = require('path').join;
|
|
||||||
const boxen = require('boxen');
|
|
||||||
const chalk = require('chalk');
|
|
||||||
const updateNotifier = require('update-notifier');
|
|
||||||
const pkg = require('./package.json');
|
|
||||||
const meow = require('meow');
|
|
||||||
|
|
||||||
const cli = meow([
|
|
||||||
'Usage',
|
|
||||||
' bash-handbook',
|
|
||||||
'',
|
|
||||||
'Options',
|
|
||||||
' --lang, -l Translation language',
|
|
||||||
'',
|
|
||||||
'Examples',
|
|
||||||
' bash-handbook',
|
|
||||||
' bash-handbook --lang pt-br'
|
|
||||||
], {
|
|
||||||
string: [
|
|
||||||
'lang'
|
|
||||||
],
|
|
||||||
alias: {
|
|
||||||
l: 'lang',
|
|
||||||
h: 'help'
|
|
||||||
},
|
|
||||||
default: {
|
|
||||||
lang: ''
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const boxenOpts = {
|
|
||||||
borderColor: 'yellow',
|
|
||||||
margin: {
|
|
||||||
bottom: 1
|
|
||||||
},
|
|
||||||
padding: {
|
|
||||||
right: 1,
|
|
||||||
left: 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const mseeOpts = {
|
|
||||||
paragraphEnd: '\n\n'
|
|
||||||
};
|
|
||||||
|
|
||||||
const notifier = updateNotifier({ pkg });
|
|
||||||
|
|
||||||
process.env.PAGER = process.env.PAGER || 'less';
|
|
||||||
process.env.LESS = process.env.LESS || 'FRX';
|
|
||||||
|
|
||||||
const lang = cli.flags.lang
|
|
||||||
.toLowerCase()
|
|
||||||
.split('-')
|
|
||||||
.map((l, i) => i === 0 ? l : l.toUpperCase())
|
|
||||||
.join('-');
|
|
||||||
|
|
||||||
const translation = join(__dirname, !lang ? './README.md' : `./README-${lang}.md`);
|
|
||||||
|
|
||||||
fs.stat(translation, function (err, stats) {
|
|
||||||
if (err) {
|
|
||||||
console.log('The %s translation does not exist', chalk.bold(lang));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.createReadStream(translation)
|
|
||||||
.pipe(obj(function (chunk, enc, cb) {
|
|
||||||
const message = [];
|
|
||||||
|
|
||||||
if (notifier.update) {
|
|
||||||
message.push(`Update available: {green.bold ${notifier.update.latest}} {dim current: ${notifier.update.current}}`);
|
|
||||||
message.push(`Run {blue npm install -g ${pkg.name}} to update.`);
|
|
||||||
this.push(boxen(message.join('\n'), boxenOpts));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.push(msee.parse(chunk.toString(), mseeOpts));
|
|
||||||
cb();
|
|
||||||
}))
|
|
||||||
.pipe(pager());
|
|
||||||
});
|
|
51
wtfpython-pypi/content.md
vendored
51
wtfpython-pypi/content.md
vendored
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
[![WTFPL 2.0][license-image]][license-url]
|
[![WTFPL 2.0][license-image]][license-url]
|
||||||
|
|
||||||
|
Translations: [Chinese 中文](https://github.com/leisurelicht/wtfpython-cn)
|
||||||
|
|
||||||
Python, being a beautifully designed high-level and interpreter-based programming language, provides us with many features for the programmer's comfort. But sometimes, the outcomes of a Python snippet may not seem obvious to a regular user at first sight.
|
Python, being a beautifully designed high-level and interpreter-based programming language, provides us with many features for the programmer's comfort. But sometimes, the outcomes of a Python snippet may not seem obvious to a regular user at first sight.
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ While some of the examples you see below may not be WTFs in the truest sense, bu
|
|||||||
|
|
||||||
If you're an experienced Python programmer, you can take it as a challenge to get most of them right in first attempt. You may be already familiar with some of these examples, and I might be able to revive sweet old memories of yours being bitten by these gotchas :sweat_smile:
|
If you're an experienced Python programmer, you can take it as a challenge to get most of them right in first attempt. You may be already familiar with some of these examples, and I might be able to revive sweet old memories of yours being bitten by these gotchas :sweat_smile:
|
||||||
|
|
||||||
If you're a returning reader, you can learn about the new modifications [here](https://github.com/satwikkansal/wtfpython/releases/).
|
PS: If you're a returning reader, you can learn about the new modifications [here](https://github.com/satwikkansal/wtfpython/releases/).
|
||||||
|
|
||||||
So, here we go...
|
So, here we go...
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ So, here we go...
|
|||||||
- [▶ Yes, it exists!](#-yes-it-exists)
|
- [▶ Yes, it exists!](#-yes-it-exists)
|
||||||
- [▶ Inpinity *](#-inpinity-)
|
- [▶ Inpinity *](#-inpinity-)
|
||||||
- [▶ Mangling time! *](#-mangling-time-)
|
- [▶ Mangling time! *](#-mangling-time-)
|
||||||
- [Section: Miscallaneous](#section-miscallaneous)
|
- [Section: Miscellaneous](#section-miscellaneous)
|
||||||
- [▶ `+=` is faster](#--is-faster)
|
- [▶ `+=` is faster](#--is-faster)
|
||||||
- [▶ Let's make a giant string!](#-lets-make-a-giant-string)
|
- [▶ Let's make a giant string!](#-lets-make-a-giant-string)
|
||||||
- [▶ Explicit typecast of strings](#-explicit-typecast-of-strings)
|
- [▶ Explicit typecast of strings](#-explicit-typecast-of-strings)
|
||||||
@ -200,10 +201,10 @@ Makes sense, right?
|
|||||||
+ In the snippets above, strings are implicitly interned. The decision of when to implicitly intern a string is implementation dependent. There are some facts that can be used to guess if a string will be interned or not:
|
+ In the snippets above, strings are implicitly interned. The decision of when to implicitly intern a string is implementation dependent. There are some facts that can be used to guess if a string will be interned or not:
|
||||||
* All length 0 and length 1 strings are interned.
|
* All length 0 and length 1 strings are interned.
|
||||||
* Strings are interned at compile time (`'wtf'` will be interned but `''.join(['w', 't', 'f']` will not be interned)
|
* Strings are interned at compile time (`'wtf'` will be interned but `''.join(['w', 't', 'f']` will not be interned)
|
||||||
* Strings that are not composed of ASCII letters, digits or underscores, are not interned. This explains why `'wtf!'` was not interned due to `!`.
|
* Strings that are not composed of ASCII letters, digits or underscores, are not interned. This explains why `'wtf!'` was not interned due to `!`. Cpython implementation of this rule can be found [here](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19)
|
||||||
<img src="/images/string-intern/string_intern.png" alt="">
|
<img src="/images/string-intern/string_intern.png" alt="">
|
||||||
+ When `a` and `b` are set to `"wtf!"` in the same line, the Python interpreter creates a new object, then references the second variable at the same time. If you do it on separate lines, it doesn't "know" that there's already `wtf!` as an object (because `"wtf!"` is not implicitly interned as per the facts mentioned above). It's a compiler optimization and specifically applies to the interactive environment.
|
+ When `a` and `b` are set to `"wtf!"` in the same line, the Python interpreter creates a new object, then references the second variable at the same time. If you do it on separate lines, it doesn't "know" that there's already `wtf!` as an object (because `"wtf!"` is not implicitly interned as per the facts mentioned above). It's a compiler optimization and specifically applies to the interactive environment.
|
||||||
+ Constant folding is a technique for [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) in Python. This means the expression `'a'*20` is replaced by `'aaaaaaaaaaaaaaaaaaaa'` during compilation to reduce few clock cycles during runtime. But since the python bytecode generated after compilation is stored in `.pyc` files, the strings greater than length of 20 are discarded for peephole optimization (Why? Imagine the size of `.pyc` file generated as a result of the expression `'a'*10**10`)
|
+ Constant folding is a technique for [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) in Python. This means the expression `'a'*20` is replaced by `'aaaaaaaaaaaaaaaaaaaa'` during compilation to reduce few clock cycles during runtime. Constant folding only occurs for strings having length less than 20. (Why? Imagine the size of `.pyc` file generated as a result of the expression `'a'*10**10`). [Here's](https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288) the implementation source for the same.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -241,7 +242,7 @@ some_dict[5] = "Python"
|
|||||||
True
|
True
|
||||||
```
|
```
|
||||||
**Note:** Objects with different values may also have same hash (known as hash collision).
|
**Note:** Objects with different values may also have same hash (known as hash collision).
|
||||||
* When the statement `some_dict[5] = "Python"` is executed, the existing value "JavaScript" is overwritten with "Python" because Python recongnizes `5` and `5.0` as the same keys of the dictionary `some_dict`.
|
* When the statement `some_dict[5] = "Python"` is executed, the existing value "JavaScript" is overwritten with "Python" because Python recognizes `5` and `5.0` as the same keys of the dictionary `some_dict`.
|
||||||
* This StackOverflow [answer](https://stackoverflow.com/a/32211042/4354153) explains beautifully the rationale behind it.
|
* This StackOverflow [answer](https://stackoverflow.com/a/32211042/4354153) explains beautifully the rationale behind it.
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -303,9 +304,17 @@ True
|
|||||||
**Output:**
|
**Output:**
|
||||||
```py
|
```py
|
||||||
>>> WTF() is WTF()
|
>>> WTF() is WTF()
|
||||||
I I D D
|
I
|
||||||
|
I
|
||||||
|
D
|
||||||
|
D
|
||||||
|
False
|
||||||
>>> id(WTF()) == id(WTF())
|
>>> id(WTF()) == id(WTF())
|
||||||
I D I D
|
I
|
||||||
|
D
|
||||||
|
I
|
||||||
|
D
|
||||||
|
True
|
||||||
```
|
```
|
||||||
As you may observe, the order in which the objects are destroyed is what made all the difference here.
|
As you may observe, the order in which the objects are destroyed is what made all the difference here.
|
||||||
|
|
||||||
@ -530,7 +539,7 @@ And when the `board` is initialized by multiplying the `row`, this is what happe
|
|||||||
We can avoid this scenario here by not using `row` variable to generate `board`. (Asked in [this](https://github.com/satwikkansal/wtfpython/issues/68) issue).
|
We can avoid this scenario here by not using `row` variable to generate `board`. (Asked in [this](https://github.com/satwikkansal/wtfpython/issues/68) issue).
|
||||||
|
|
||||||
```py
|
```py
|
||||||
>>> board = [(['']*3)*3] # board = = [['']*3 for _ in range(3)]
|
>>> board = [['']*3 for _ in range(3)]
|
||||||
>>> board[0][0] = "X"
|
>>> board[0][0] = "X"
|
||||||
>>> board
|
>>> board
|
||||||
[['X', '', ''], ['', '', ''], ['', '', '']]
|
[['X', '', ''], ['', '', ''], ['', '', '']]
|
||||||
@ -547,7 +556,7 @@ for x in range(7):
|
|||||||
def some_func():
|
def some_func():
|
||||||
return x
|
return x
|
||||||
funcs.append(some_func)
|
funcs.append(some_func)
|
||||||
results.append(some_func())
|
results.append(some_func()) # note the function call here
|
||||||
|
|
||||||
funcs_results = [func() for func in funcs]
|
funcs_results = [func() for func in funcs]
|
||||||
```
|
```
|
||||||
@ -766,10 +775,10 @@ for item in mixed_list:
|
|||||||
|
|
||||||
**Output:**
|
**Output:**
|
||||||
```py
|
```py
|
||||||
>>> booleans_found_so_far
|
|
||||||
0
|
|
||||||
>>> integers_found_so_far
|
>>> integers_found_so_far
|
||||||
4
|
4
|
||||||
|
>>> booleans_found_so_far
|
||||||
|
0
|
||||||
```
|
```
|
||||||
|
|
||||||
2\.
|
2\.
|
||||||
@ -830,7 +839,7 @@ class C(A):
|
|||||||
pass
|
pass
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ouptut:**
|
**Output:**
|
||||||
```py
|
```py
|
||||||
>>> A.x, B.x, C.x
|
>>> A.x, B.x, C.x
|
||||||
(1, 1, 1)
|
(1, 1, 1)
|
||||||
@ -1148,7 +1157,7 @@ str
|
|||||||
>>> s = SomeClass('s')
|
>>> s = SomeClass('s')
|
||||||
>>> some_dict[s] = 40
|
>>> some_dict[s] = 40
|
||||||
>>> some_dict
|
>>> some_dict
|
||||||
{'s': 40}
|
{'s': 40, 's': 42}
|
||||||
>>> keys = list(some_dict.keys())
|
>>> keys = list(some_dict.keys())
|
||||||
>>> type(keys[0]), type(keys[1])
|
>>> type(keys[0]), type(keys[1])
|
||||||
(__main__.SomeClass, str)
|
(__main__.SomeClass, str)
|
||||||
@ -1895,7 +1904,7 @@ Sshh.. It's a super secret.
|
|||||||
#### 💡 Explanation:
|
#### 💡 Explanation:
|
||||||
+ `antigravity` module is one of the few easter eggs released by Python developers.
|
+ `antigravity` module is one of the few easter eggs released by Python developers.
|
||||||
+ `import antigravity` opens up a web browser pointing to the [classic XKCD comic](http://xkcd.com/353/) about Python.
|
+ `import antigravity` opens up a web browser pointing to the [classic XKCD comic](http://xkcd.com/353/) about Python.
|
||||||
+ Well, there's more to it. There's **another easter egg inside the easter egg**. If look at the [code](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), there's a function defined that purports to implement the [XKCD's geohashing algorithm](https://xkcd.com/426/).
|
+ Well, there's more to it. There's **another easter egg inside the easter egg**. If you look at the [code](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), there's a function defined that purports to implement the [XKCD's geohashing algorithm](https://xkcd.com/426/).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -2115,7 +2124,7 @@ AttributeError: 'Yo' object has no attribute '__honey'
|
|||||||
True
|
True
|
||||||
```
|
```
|
||||||
|
|
||||||
Why did `Yo()._Yo__honey` worked? Only Indian readers would understand.
|
Why did `Yo()._Yo__honey` work? Only Indian readers would understand.
|
||||||
|
|
||||||
#### 💡 Explanation:
|
#### 💡 Explanation:
|
||||||
|
|
||||||
@ -2127,7 +2136,7 @@ Why did `Yo()._Yo__honey` worked? Only Indian readers would understand.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Section: Miscallaneous
|
## Section: Miscellaneous
|
||||||
|
|
||||||
|
|
||||||
### ▶ `+=` is faster
|
### ▶ `+=` is faster
|
||||||
@ -2350,7 +2359,7 @@ The idea and design for this collection were initially inspired by Denys Dovhan'
|
|||||||
* https://stackoverflow.com/questions/530530/python-2-x-gotchas-and-landmines
|
* https://stackoverflow.com/questions/530530/python-2-x-gotchas-and-landmines
|
||||||
* https://stackoverflow.com/questions/1011431/common-pitfalls-in-python
|
* https://stackoverflow.com/questions/1011431/common-pitfalls-in-python
|
||||||
* https://www.python.org/doc/humor/
|
* https://www.python.org/doc/humor/
|
||||||
* https://www.satwikkansal.xyz/archives/posts/python/My-Python-archives/
|
* https://www.codementor.io/satwikkansal/python-practices-for-efficient-code-performance-memory-and-usability-aze6oiq65
|
||||||
|
|
||||||
# 🎓 License
|
# 🎓 License
|
||||||
|
|
||||||
@ -2365,12 +2374,12 @@ The idea and design for this collection were initially inspired by Denys Dovhan'
|
|||||||
|
|
||||||
If you have any wtfs, ideas or suggestions, please share.
|
If you have any wtfs, ideas or suggestions, please share.
|
||||||
|
|
||||||
## Want to share wtfpython with friends?
|
## Surprise your geeky pythonist friends?
|
||||||
|
|
||||||
You can use these quick links for Twitter and Linkedin.
|
You can use these quick links to recommend wtfpython to your friends,
|
||||||
|
|
||||||
[Twitter](https://twitter.com/intent/tweet?url=https://github.com/satwikkansal/wtfpython&hastags=python,wtfpython) |
|
[Twitter](https://twitter.com/intent/tweet?url=https://github.com/satwikkansal/wtfpython&hastags=python,wtfpython)
|
||||||
[Linkedin](https://www.linkedin.com/shareArticle?url=https://github.com/satwikkansal&title=What%20the%20f*ck%20Python!&summary=An%20interesting%20collection%20of%20subtle%20and%20tricky%20Python%20snippets.)
|
| [Linkedin](https://www.linkedin.com/shareArticle?url=https://github.com/satwikkansal&title=What%20the%20f*ck%20Python!&summary=An%20interesting%20collection%20of%20subtle%20and%20tricky%20Python%20snippets.)
|
||||||
|
|
||||||
## Need a pdf version?
|
## Need a pdf version?
|
||||||
|
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
|
from os.path import dirname, join, realpath
|
||||||
|
|
||||||
import pydoc
|
import pydoc
|
||||||
try:
|
try:
|
||||||
from urllib.request import urlretrieve
|
from urllib.request import urlretrieve
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from urllib import urlretrieve
|
from urllib import urlretrieve
|
||||||
|
|
||||||
url = ("https://raw.githubusercontent.com/satwikkansal/"
|
url = ("http://raw.githubusercontent.com/satwikkansal/"
|
||||||
"wtfpython/master/README.md")
|
"wtfpython/master/README.md")
|
||||||
file_name = "content.md"
|
|
||||||
|
file_path = join(dirname(dirname(realpath(__file__))), "content.md")
|
||||||
|
|
||||||
|
|
||||||
def fetch_updated_doc():
|
def fetch_updated_doc():
|
||||||
try:
|
try:
|
||||||
print("Fetching the latest version...")
|
print("Fetching the latest version...")
|
||||||
urlretrieve(url, file_name)
|
urlretrieve(url, file_path)
|
||||||
print("Done!")
|
print("Done!")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
@ -21,7 +24,7 @@ def fetch_updated_doc():
|
|||||||
|
|
||||||
|
|
||||||
def render_doc():
|
def render_doc():
|
||||||
with open(file_name, 'r') as f:
|
with open(file_path, 'r', encoding="utf-8") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
pydoc.pager(content)
|
pydoc.pager(content)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user