aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps
diff options
context:
space:
mode:
authorGravatar kosayoda <[email protected]>2021-04-15 14:21:32 +0800
committerGravatar kosayoda <[email protected]>2021-04-15 14:21:32 +0800
commit71b902006769d15095ed7d638bcc3729153184ee (patch)
treea4a8fee7f7c5729b60ac784addbded093c3760d1 /pydis_site/apps
parentAvoid duplicate entries for page and category. (diff)
Migrate Python guides.
Diffstat (limited to 'pydis_site/apps')
-rw-r--r--pydis_site/apps/content/resources/guides/python-guides/_info.yml3
-rw-r--r--pydis_site/apps/content/resources/guides/python-guides/discordpy.md230
-rw-r--r--pydis_site/apps/content/resources/guides/python-guides/mutability.md52
-rw-r--r--pydis_site/apps/content/resources/guides/python-guides/parameters-and-arguments.md289
4 files changed, 574 insertions, 0 deletions
diff --git a/pydis_site/apps/content/resources/guides/python-guides/_info.yml b/pydis_site/apps/content/resources/guides/python-guides/_info.yml
new file mode 100644
index 00000000..67730962
--- /dev/null
+++ b/pydis_site/apps/content/resources/guides/python-guides/_info.yml
@@ -0,0 +1,3 @@
+title: Python Guides
+description: Guides related to the Python Programming Language.
+icon: fab fa-python
diff --git a/pydis_site/apps/content/resources/guides/python-guides/discordpy.md b/pydis_site/apps/content/resources/guides/python-guides/discordpy.md
new file mode 100644
index 00000000..93e43867
--- /dev/null
+++ b/pydis_site/apps/content/resources/guides/python-guides/discordpy.md
@@ -0,0 +1,230 @@
+---
+title: Discord.py Learning Guide
+description: A learning guide for the discord.py bot framework written by members of our community.
+icon: fab fa-python
+toc: 2
+---
+
+<!-- discord.py Badge -->
+<a href="https://github.com/Rapptz/discord.py/">
+ <div class="tags has-addons">
+ <span class="tag is-dark">discord.py</span><span class="tag is-info">≥1.0</span>
+ </div>
+</a>
+
+Interest in creating a Discord bot is a common introduction to the world of programming in our community.
+
+Using it as your first project in programming while trying to learn is a double-edged sword.
+A large number of concepts need to be understood before becoming proficient at creating a bot, making the journey of learning and completing the project more arduous than more simple projects designed specifically for beginners.
+However in return, you get the opportunity to expose yourself to many more aspects of Python than you normally would and so it can be an amazingly rewarding experience when you finally reach your goal.
+
+Another excellent aspect of building bots is that it has a huge scope as to what you can do with it, almost only limited by your own imagination.
+This means you can continue to learn and apply more advanced concepts as you grow as a programmer while still building bots, so learning it can be a useful and enjoyable skillset.
+
+This page provides resources to make the path to learning as clear and easy as possible, and collates useful examples provided by the community that may address common ideas and concerns that are seen when working on Discord bots.
+
+## Essential References
+
+Official Documentation: [https://discord.py.readthedocs.io](https://discordpy.readthedocs.io/)
+
+Source Repository: [https://github.com/Rapptz/discord.py](https://github.com/Rapptz/discord.py)
+
+## Creating a Discord Bot Account
+
+1. Navigate to [https://discord.com/developers/applications](https://discord.com/developers/applications) and log in.
+2. Click on `New Application`.
+3. Enter the application's name.
+4. Click on `Bot` on the left side settings menu.
+5. Click `Add Bot` and confirm with `Yes, do it!`.
+
+### Client ID
+Your Client ID is the same as the User ID of your Bot.
+You will need this when creating an invite URL.
+
+You can find your Client ID located on the `General Information` settings page of your Application, under the `Name` field.
+
+Your Client ID is not a secret, and does not need to be kept private.
+
+### Bot Token
+
+Your Bot Token is the token that authorises your Bot account with the API.
+Think of it like your Bot's API access key.
+With your token, you can interact with any part of the API that's available to bots.
+
+You can find your Bot Token located on the Bot settings page of your Application, under the Username field.
+You can click the Copy button to copy it without revealing it manually.
+
+**Your Bot Token is a secret, and must be kept private.**
+If you leak your token anywhere other people has access to see it, no matter the duration, you should reset your Bot Token.
+
+To reset your token, go to the Bot settings page of your Application, and click the Regenerate button.
+Be sure to update the token you're using for your bot script to this new one, as the old one will not work anymore.
+
+### Permissions Integer
+
+Discord Permissions are typically represented by a Permissions Integer which represents all the Permissions that have been allowed.
+
+You can find a reference to all the available Discord Permissions, their bitwise values and their descriptions here:
+[https://discordapp.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags](https://discordapp.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags)
+
+If you want to create your own Permissions Integer, you can generate it in the `Bot` settings page of your Application, located at the bottom of the page.
+
+Tick the permissions you want to be allowing, and it'll update the `Permissions Integer` field, which you can use in your Bot Invite URL to set your bot's default permissions when users go to invite it.
+
+### Bot Invite URL
+
+Bot's cannot use a server invite link. Instead, they have to be invited by a member with the Manage Server permission.
+
+The Bot Invite URL is formatted like:
+`https://discordapp.com/oauth2/authorize?client_id={CLIENT_ID}&scope=bot&permissions={PERMISSIONS_INTEGER}`
+
+You can create the Invite URL for your bot by replacing:
+
+* `{CLIENT_ID}` with your [Client ID](#client-id)
+* `{PERMISSIONS_INTEGER}` with the [Permissions Integer](#permissions-integer)
+
+You can also generate it with the [Permissions Calculator](https://discordapi.com/permissions.html tool) tool.
+
+## Using the Basic Client (`discord.Client`) { data-toc-label="Using the Basic Client" }
+
+Below are the essential resources to read over to get familiar with the basic functionality of `discord.py`.
+
+* [Basic event usage](https://discordpy.readthedocs.io/en/latest/intro.html#basic*concepts)
+* [Simple bot walkthrough](https://discordpy.readthedocs.io/en/latest/quickstart.html#a*minimal*bot)
+* [Available events reference](https://discordpy.readthedocs.io/en/latest/api.html#event*reference)
+* [General API reference](https://discordpy.readthedocs.io/en/latest/api.html)
+
+## Using the Commands Extension (`commands.Bot`) { data-toc-label="Using the Commands Extension" }
+
+The Commands Extension has a explanatory documentation walking you through not only what it is and it's basic usage, but also more advanced concepts.
+Be sure to read the prose documentation in full at:
+[https://discordpy.readthedocs.io/en/latest/ext/commands/commands.html](https://discordpy.readthedocs.io/en/latest/ext/commands/commands.html)
+
+It fully covers:
+* How to create bot using the Commands Extension
+* How to define commands and their arguments
+* What the Context object is
+* Argument Converters
+* Error Handling basics
+* Command checks
+
+You will also need to reference the following resources:
+* [Commands Extension exclusive events](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#event-reference)
+* [Commands Extension API reference](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html)
+
+## FAQ
+
+The documentation covers some basic FAQ's, and they are recommended to be read beforehand, and referenced before asking for help in case it covers your issue:
+[https://discordpy.readthedocs.io/en/latest/faq.html](https://discordpy.readthedocs.io/en/latest/faq.html)
+
+## Usage Examples
+
+### Official Examples and Resources
+
+The official examples can be found on the [source repository](https://github.com/Rapptz/discord.py/tree/master/examples).
+
+The most commonly referenced examples are:
+
+* [Basic Commands Extension Bot](https://github.com/Rapptz/discord.py/blob/master/examples/basic_bot.py)
+* [Background Task Example](https://github.com/Rapptz/discord.py/blob/master/examples/background_task.py)
+
+### Permissions Documentation
+
+* [Role Management 101](https://support.discordapp.com/hc/en-us/articles/214836687-Role-Management-101)
+* [Full Permissions Documentation](https://discordapp.com/developers/docs/topics/permissions)
+
+### Community Examples and Resources
+
+The `discord.py` developer community over time have shared examples and references with each other.
+The following are a collated list of the most referenced community examples.
+
+#### Extensions / Cogs
+* [Extension/Cog Example](https://gist.github.com/EvieePy/d78c061a4798ae81be9825468fe146be) - *Credit to EvieePy*
+* [Available Cog Methods](https://gist.github.com/Ikusaba-san/69115b79d33e05ed07ec4a4f14db83b1) - *Credit to MIkusaba*
+
+#### Error Handling
+* [Decent Error Handling Example](https://gist.github.com/EvieePy/7822af90858ef65012ea500bcecf1612) - *Credit to EvieePy*
+
+#### Embeds
+* [Embed Live Designer and Visualiser](https://leovoel.github.io/embed-visualizer/) - *Credit to leovoel*
+* [Embed Element Reference](https://cdn.discordapp.com/attachments/84319995256905728/252292324967710721/embed.png)
+![Embed Element Reference](/static/images/content/discordpy_embed.webp){: width="200" }
+
+##### Using Local Images in Embeds
+```py
+filename = "image.png"
+
+f = discord.File("some_file_path", filename=filename)
+embed = discord.Embed()
+
+embed.set_image(url=f"attachment://{filename}")
+await messagable.send(file=f, embed=embed)
+```
+
+##### Embed Limits
+
+| **Element** | **Characters** |
+| -------------- | ---------------------- |
+| Title | 256 |
+| Field Name | 256 |
+| Field Value | 1024 |
+| Description | 2048 |
+| Footer | 2048 |
+| **Entire Embed** | **6000**
+
+| **Element** | **Count** |
+| -------------- | ---------------------- |
+| Fields | 25 |
+
+#### Emoji
+
+- [Bot's Using Emoji](https://gist.github.com/scragly/b8d20aece2d058c8c601b44a689a47a0)
+
+#### Activity Presence
+
+- [Setting Bot's Discord Activity](https://gist.github.com/scragly/2579b4d335f87e83fbacb7dfd3d32828)
+
+#### Image Processing
+
+- [PIL Image Processing Example Cog](https://gist.github.com/Gorialis/e89482310d74a90a946b44cf34009e88) - *Credit to Gorialis*
+
+### Systemd Service
+**botname.service**
+```ini
+[Unit]
+Description=My Bot Name
+After=network-online.target
+
+[Service]
+Type=simple
+WorkingDirectory=/your/bots/directory
+ExecStart=/usr/bin/python3 /your/bots/directory/file.py
+User=username
+Restart=on-failure
+
+[Install]
+WantedBy=network-online.target
+```
+
+**Directory**
+`/usr/local/lib/systemd/system`
+
+**Service Commands**
+Refresh systemd after unit file changes:
+`systemctl daemon-reload`
+
+Set service to start on boot:
+`systemctl enable botname`
+
+Start service now:
+`systemctl start botname`
+
+Stop service:
+`systemctl stop botname`
+
+**Viewing Logs**
+All logs:
+`journalctl -u botname`
+
+Recent logs and continue printing new logs live:
+`journalctl -fu mybot`
diff --git a/pydis_site/apps/content/resources/guides/python-guides/mutability.md b/pydis_site/apps/content/resources/guides/python-guides/mutability.md
new file mode 100644
index 00000000..19e50819
--- /dev/null
+++ b/pydis_site/apps/content/resources/guides/python-guides/mutability.md
@@ -0,0 +1,52 @@
+---
+title: Mutability and Immutability in Python
+description: "Mutable and immutable data types: What they are and how they work."
+---
+
+Consider this example:
+```python
+>>> s = "hello"
+>>> s.upper()
+'HELLO'
+>>> s
+'hello'
+```
+This might break your expectations.
+After all, you've called the `upper()` method on `s`, so why didn't it change? That's because strings are _immutable_: you can't change them in-place, only create new ones.
+In this example, `.upper()` just cannot change the string stored in `s`.
+
+How do you make `s` store `'HELLO'` instead of `'hello'` then? That's possible.
+Even though you can't change the original string, you can create a new one, which is like the old one, but with all letters in upper case.
+
+In other words, `s.upper()` doesn't change an existing string.
+It just returns a new one.
+```python
+>>> s = 'hello'
+>>> s = s.upper()
+>>> s
+'HELLO'
+```
+
+Let's examine what's going on here.
+At first, the variable `s` refers to some object, the string `'hello'`.
+
+![s refers to the string "hello"](/static/images/content/mutability/s_refers_hello.webp)
+
+When you call `s.upper()`, a new string, which contains the characters `'HELLO'`, gets created.
+![s.upper creates "HELLO"](/static/images/content/mutability/s_upper_creates_HELLO.webp)
+
+This happens even if you just call `s.upper()` without any assignment, on its own line:
+```python
+"hello".upper()
+```
+In this case, a new object will be created and discarded right away.
+
+Then the assignment part comes in: the name `s` gets disconnected from `'hello'`, and gets connected to `'HELLO'`.
+![s gets assigned to "HELLO"](/static/images/content/mutability/s_gets_assigned_to_HELLO.webp)
+
+Now we can say that `'HELLO'` is stored in the `s` variable.
+
+Then, because no variables refer to the _object_ `'hello'`, it gets eaten by the garbage collector.
+!["hello" Gets Eaten](/static/images/content/mutability/hello_gets_eaten.webp)
+
+It means that the memory reserved for that object will be freed. If that didn't happen, the 'garbage' would accumulate over time and fill up all the RAM.
diff --git a/pydis_site/apps/content/resources/guides/python-guides/parameters-and-arguments.md b/pydis_site/apps/content/resources/guides/python-guides/parameters-and-arguments.md
new file mode 100644
index 00000000..94d4609b
--- /dev/null
+++ b/pydis_site/apps/content/resources/guides/python-guides/parameters-and-arguments.md
@@ -0,0 +1,289 @@
+---
+title: Function Parameters and Arguments in Python
+description: An in-depth look at function parameters and arguments, and how to use them.
+---
+
+A Python function is utilised in two steps:
+
+1. The function definition/signature (used just once).
+2. The function invocation/call (used many times).
+
+The function definition uses parameters, whereas the function call uses arguments:
+
+```python
+def foo(this_is_a_parameter):
+ print(this_is_a_parameter)
+
+foo(this_is_an_argument)
+```
+
+An important detail to be aware of is that by default any argument used to call a function in Python can be used as both a positional and a keyword argument—just not at the same time.
+A function call may contain a mixture of positional and keyword arguments, and—unless otherwise specified—an argument can reference the parameters in the function definition positionally, or by name (keyword).
+
+# Positional Arguments
+
+```python
+def foo(a, b, c):
+ print(a, b, c)
+
+>>> foo(1, 2, 3)
+1 2 3
+```
+
+In the above function definition we have three parameters `a`, `b`, and `c`.
+
+When we invoke the function with the arguments `1`, `2`, and `3`, the function will map these values in the exact order given to the parameters in the function definition.
+With no keyword reference given they become positional arguments.
+
+# Keyword Arguments
+
+```python
+def foo(a, b, c):
+ print(a, b, c)
+
+>>> foo(1, 2, 3)
+1 2 3
+
+>>> foo(c=3, b=2, a=1)
+1 2 3
+```
+
+As you can see, `foo(1, 2, 3)` and `foo(c=3, b=2, a=1)` are identical.
+Referencing a function parameter by its name means that we are using a keyword argument.
+The order in which keyword arguments are given does not matter.
+
+# Mixing Positional and Keyword Arguments
+
+So what happens if we want to mix the positional argument mapping with keyword arguments?
+
+Python prioritises the mapping of positional arguments to their parameter names before the mapping of keywords.
+
+```python
+def foo(a, b, c):
+ print(a, b, c)
+
+>>> foo(1, c=3, b=2)
+1 2 3
+```
+
+Passing a keyword argument using the name of a parameter that has already been given will not work:
+
+```python
+>>> foo(1, 2, a=3)
+TypeError: foo() got multiple values for argument 'a'
+
+>>> foo(1, b=2, b=3)
+SyntaxError: keyword argument repeated
+```
+
+Attempting to pass positional arguments after a keyword argument will also not work:
+
+```python
+>>> foo(a=1, 2, 3)
+SyntaxError: positional argument follows keyword argument
+```
+
+# Default Parameter Values
+
+Although the syntax is similar, these are not to be confused with keyword arguments.
+Default parameter values appear within the function definition and allow us to conveniently set a default value. This means that if any argument is omitted, its default value will be used as the argument.
+
+```python
+def foo(a=0, b=0, c=0):
+ print(a, b, c)
+
+>>> foo()
+0 0 0
+
+>>> foo(1, 2, 3)
+1 2 3
+
+>>> foo(c=3, b=2)
+0 2 3
+
+>>> foo(1, c=3)
+1 0 3
+```
+
+Using default parameter values does not change how a function can be invoked with arguments:
+
+```python
+>>> foo(1, 2, a=3)
+TypeError: foo() got multiple values for argument 'a'
+
+>>> foo(1, b=2, b=3)
+SyntaxError: keyword argument repeated
+
+>>> foo(a=1, 2, 3)
+SyntaxError: positional argument follows keyword argument
+```
+
+You must specify any parameters without a default value before those with default values:
+
+```python
+def foo(a=0, b):
+ ^
+SyntaxError: non-default argument follows default argument
+```
+
+# Positional-only Parameters
+[Python 3.8](https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters) / [PEP 570](https://www.python.org/dev/peps/pep-0570/) introduces the possibility to specify which parameters are required to be positional-only via a bare `/` parameter within a function definition.
+
+```python
+def foo(a=0, b=0, /, c=0, d=0):
+ print(a, b, c, d)
+```
+
+The parameters defined before the bare `/` are now considered to be positional-only and keyword mapping will no longer work on them.
+In the above function definition `a` and `b` are now positional-only parameters.
+
+These function calls will still work:
+
+```python
+>>> foo()
+0 0 0 0
+
+>>> foo(1)
+1 0 0 0
+
+>>> foo(1, 2, 3, 4)
+1 2 3 4
+
+>>> foo(1, 2, d=4, c=3)
+1 2 3 4
+
+>>> foo(1, d=4, c=3)
+1 0 3 4
+
+>>> foo(c=3, d=4)
+0 0 3 4
+```
+
+However, attempting to pass keyword arguments for `a` or `b` will fail:
+
+```python
+>>> foo(1, b=2, c=3, d=4)
+TypeError: foo() got some positional-only arguments passed as keyword arguments: 'b'
+```
+
+### Q: Why is this useful?
+
+#### Keyword Argument Freedom
+
+Passing a keyword argument using the name of a parameter that has already been given will not work.
+This becomes an issue if we require keyword arguments that use the same parameter names as defined in the function signature, such as via callback functions.
+
+```python
+def foo(a, **kwargs):
+ print(a, kwargs)
+
+>>> foo(a=1, a=2)
+SyntaxError: keyword argument repeated
+
+>>> foo(1, a=2)
+TypeError: foo() got multiple values for argument 'a'
+```
+
+#### Backwards Compatibility
+
+Because Python allows that an argument by default can be either positional or keyword, a user is free to choose either option.
+Unfortunately, this forces the author to keep the given parameter names as they are if they wish to support backwards compatibility, as changing the parameter names can cause dependent code to break.
+Enforcing positional-only parameters gives the author the freedom to separate the variable name used within the function from its usage outside of it.
+
+```python
+def calculate(a, b):
+ # do something with a and b
+
+>>> calculate(1, 2)
+```
+
+A user could call this function using `a` or `b` as keywords, which the author may have not intended:
+
+```python
+>>> calculate(a=1, b=2)
+```
+
+However, by using `/`, the user will no longer be able to invoke using `a` or `b` as keywords, and the author is also free to rename these parameters:
+
+```python
+def calculate(x, y, /):
+ # do something with x and y
+
+>>> calculate(1, 2)
+```
+
+# Keyword-only Parameters
+
+Similarly to enforcing positional-only parameters, we can also enforce keyword-only parameters using a bare `*` parameter.
+The parameters defined after the bare `*` are now considered to be keyword-only.
+
+```python
+def foo(a=0, b=0, /, c=0, *, d=0):
+ print(a, b, c, d)
+
+>>> foo()
+0 0 0 0
+
+>>> foo(1, 2, 3)
+1 2 3 0
+
+>>> foo(1, 2, d=4, c=3)
+1 2 3 4
+
+>>> foo(1, d=4, c=3)
+1 0 3 4
+```
+
+Although `c` can be either a positional or keyword argument, if we attempt to pass `d` as a non-keyword argument, it will fail:
+
+```python
+>>> foo(1, 2, 3, 4)
+TypeError: foo() takes from 0 to 3 positional arguments but 4 were given
+```
+
+At least one named parameter must be provided after a bare `*` parameter.
+Writing a function definition similar to what is shown below would not make sense, as without the context of a named parameter the bare `*` can simply be omitted.
+
+```python
+def foo(a=0, *, **kwargs):
+ ^
+SyntaxError: named arguments must follow bare *
+```
+
+### Q: Why is this useful?
+
+The main benefit of using keyword-only parameters is when they are used together with positional-only parameters to remove ambiguity.
+
+However, it may sometimes also be desirable to use keyword-only arguments on their own.
+If we were to expose a function as part of an API, we may want the parameter names to carry explicit meaning.
+
+Without using keyword names when invoking the function it can be unclear as to what the provided arguments are for.
+Additionally, a user could also choose to interchange positional arguments with keyword arguments, which can potentially add to the confusion.
+
+```python
+def update(identity=None, name=None, description=None):
+ # handle the parameters
+
+>>> update("value 1", "value 2", "value 3")
+
+>>> update(1234, "value 1", description="value 2")
+```
+
+Enforcing the keyword names is clearer, as it carries context without needing to look at the function definition:
+
+```python
+def update(*, identity=None, name=None, description=None):
+ # handle the parameters
+
+>>> update(identity=1234, name="value 1", description="value 2")
+```
+
+# Summary
+
+* Unless otherwise specified, an argument can be both positional and keyword.
+* Positional arguments, when provided, must be in sequence.
+* Positional arguments must be used before keyword arguments.
+* Keyword arguments may be in any order.
+* A default parameter value is used when the argument is omitted.
+* A bare `/` used as a parameter in a function definition enforces positional-only parameters to its left.
+* A bare `*` used as a parameter in a function definition enforces keyword-only parameters to its right.