Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/improve configuration #75

Merged
merged 80 commits into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
b5c5417
feat: rewrite the entire configuration system to use marshmallow and …
onerandomusername Sep 19, 2021
6a1b0c2
config: remove config_default.toml since its now part of the classes
onerandomusername Sep 19, 2021
5afc196
fix: add missing items to the configuration
onerandomusername Sep 19, 2021
f8fabf5
fix: have a test token in the pytest env
onerandomusername Sep 19, 2021
6cc4e20
enable slots on cfg classes, fix colour converter, properly prevent t…
onerandomusername Sep 19, 2021
82b1c73
fix: remove unused class definitions
onerandomusername Sep 19, 2021
4a80406
config: add autogenerated default cfg toml file
onerandomusername Sep 19, 2021
311ff54
fix: properly deserialize discord.Colour to a string representation
onerandomusername Sep 20, 2021
62aa7dc
feat: add configuration via a yaml cfg file
onerandomusername Sep 20, 2021
e4d9e1e
fix: allow log level 50, as documented
onerandomusername Sep 20, 2021
70128af
feat: made testable config system by refactor config file loading
onerandomusername Sep 20, 2021
4707d6c
tools: add pre-commit hook to automatically export default config
onerandomusername Sep 20, 2021
26cc817
tools: automatically export required environment varaibles to .env.te…
onerandomusername Sep 20, 2021
b8d7080
tools: add app.json to configuration exports
onerandomusername Sep 20, 2021
19ddc22
minor: manaually update references to configuration files
onerandomusername Sep 20, 2021
06aad80
fix: add missing modmail dependencies to additional hook dependencies
onerandomusername Sep 20, 2021
cc50262
fix: no configuration files now loads the default config
onerandomusername Sep 20, 2021
bdc7d42
fix: create a Config instance when adding it to the bot
onerandomusername Sep 20, 2021
29de36e
fix: load prefix from modmail_config.toml if not in .env
onerandomusername Sep 20, 2021
2166f8c
fix: ignore extra configuration variables
onerandomusername Sep 20, 2021
be6b698
minor: use attr helper method instead of reimplementing it
onerandomusername Sep 20, 2021
4a367c4
chore: switch _load_config to pack positional args rather than requir…
onerandomusername Sep 20, 2021
4e085d7
fix: rewrite environment variable parser to support all configuration…
onerandomusername Sep 21, 2021
4495938
feat: add ConfigMetadata part 1
onerandomusername Sep 21, 2021
0085f2a
fix recursive dict update overriding set values
onerandomusername Sep 21, 2021
9417d3c
chore: update export docstring
onerandomusername Sep 21, 2021
bb1d956
fix: respect priorty of configuration sources
onerandomusername Sep 21, 2021
d5f1290
fix pre-commit maybe
onerandomusername Sep 21, 2021
f3c3326
nit: rename config class Bot to BotCfg to prevent future confusion
onerandomusername Sep 21, 2021
6e14be0
fix: add ConfigMetadata part 2
onerandomusername Sep 21, 2021
c05e0bb
chore: remove unused dict manipulation method
onerandomusername Sep 21, 2021
444aca1
chore: implement new metadata options on cfg default export
onerandomusername Sep 21, 2021
014e9aa
tests: add config loading tests
onerandomusername Sep 22, 2021
2a2b9dc
feat: add configuration manager cog
onerandomusername Sep 22, 2021
9eeee2e
migrate some existing values to new configuration
onerandomusername Sep 22, 2021
d6cbf86
minor: hide frozen values which can't be changed from the configuration
onerandomusername Sep 22, 2021
249fa5e
feat: rudimentary setting and getting configuration status
onerandomusername Sep 22, 2021
a3402a8
refactor getvalue
onerandomusername Sep 22, 2021
21a46d4
fix: don't load the .env file to the environment
onerandomusername Sep 24, 2021
a22f51a
minor: change config pre-commit hook to exit with 1 if files edited
onerandomusername Sep 24, 2021
1c7dd19
fix precommit requirements
onerandomusername Sep 25, 2021
dd0e287
config: allow emojis to be set (needs more work)
onerandomusername Sep 25, 2021
76ff3cd
nit: fix typo in variable name
onerandomusername Oct 4, 2021
9409421
nit: typing, formatting, and comment changes
onerandomusername Oct 4, 2021
627e650
fix: make errors more helpful if config dependencies are not installed
onerandomusername Oct 4, 2021
4b8d288
Merge branch 'main' into feat/improve-configuration
onerandomusername Nov 7, 2021
94b14e0
scripts: show diff when exporting config edits files
onerandomusername Nov 7, 2021
4117dcc
fix: no more weird new lines
onerandomusername Nov 7, 2021
7743899
Merge branch 'main' into feat/improve-configuration
onerandomusername Nov 15, 2021
003177e
minor(config): touch up the visual UI
onerandomusername Nov 15, 2021
b4e0b7d
fix: update prefix when configured prefix is updated
onerandomusername Nov 15, 2021
d644a96
minor fixes to export config script
onerandomusername Nov 15, 2021
52a339d
nit: use `dictionary` instead of `dit` to not look like a typo
onerandomusername Nov 15, 2021
0937a13
config: rename .env.template to template.env
onerandomusername Nov 15, 2021
3c60d4c
config(docs): document configuration loading priority
onerandomusername Nov 15, 2021
5ad572d
minor: touch up comments and flatten branches
onerandomusername Nov 15, 2021
8bc7c27
fix: use commands.run_converters() in the configuration manager
onerandomusername Nov 16, 2021
263ad6b
config-manager: add set-default command to reset to default
onerandomusername Nov 16, 2021
0a596b4
add set default command and offload setting config to a helper method
onerandomusername Nov 16, 2021
81c08da
fix: add missing character to filter, fix env loading
onerandomusername Nov 16, 2021
196d2a8
fix: use metadata provided converter to convert objects
onerandomusername Nov 16, 2021
ebcaf94
nits: standardize naming and make class names more self explanatory
onerandomusername Nov 16, 2021
2fd074c
config: make dotenv optional and better errors when missing variables
onerandomusername Nov 16, 2021
fa02b34
config: add logging and stabilize configuration directory
onerandomusername Nov 16, 2021
3d1986d
minor: use functools cache to cache the config
onerandomusername Nov 16, 2021
ff04a5a
use factories to generate mutable classes and add more logging
onerandomusername Nov 16, 2021
258fa1b
fix: use config.user to return configured prefix
onerandomusername Nov 16, 2021
bfe641c
chore: export the extended description after the normal description t…
onerandomusername Nov 16, 2021
fe53cf7
chore: remove operator.attrgetter and implement recursive setters an…
onerandomusername Nov 21, 2021
4e7fb22
chore: make the error spam less spammy for missing yaml file and depe…
onerandomusername Nov 21, 2021
dd2f16c
Merge branch 'main' into feat/improve-configuration
onerandomusername Nov 21, 2021
03fd57f
tests: fix environment not being replaced soon enough
onerandomusername Nov 21, 2021
f0ec067
fix: use type() instead of __class__
onerandomusername Nov 25, 2021
09a33d4
chore: address reviews
onerandomusername Jan 2, 2022
8d18ccc
Merge branch 'main' into feat/improve-configuration
onerandomusername Jan 2, 2022
4087767
remove dependency on environs
onerandomusername Apr 21, 2022
5911ff8
fix: pin discord.py
onerandomusername Apr 21, 2022
768277e
update black
onerandomusername Apr 21, 2022
62e82fa
update precommit hooks
onerandomusername Apr 21, 2022
4644d76
add configuration system to docs
onerandomusername Apr 21, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .env.template

This file was deleted.

6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ celerybeat.pid

# Environments
.env
!template.env
!/tests/modmail/test.env
.venv
env/
Expand Down Expand Up @@ -134,10 +135,11 @@ dmypy.json
.idea/

# logs
logs
/logs/

# Configuration
*config.toml
/modmail_config.toml
/modmail_config.yaml

# Custom docker compose override
docker-compose.override.yml
31 changes: 27 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
## Pre-commit setup

repos:
# its possible to put this at the bottom, but we want the pre-commit-hooks to check these files as well.
- repo: local
onerandomusername marked this conversation as resolved.
Show resolved Hide resolved
hooks:
- id: ensure-default-configuration-is-exported
name: Export default configuration
language: python
entry: poetry run python -m scripts.export_new_config_to_default_config
files: '(app\.json|template\.env|modmail\/(config\.py|default_config(\.toml|\.yaml)))$'
require_serial: true
additional_dependencies:
# so apparently these are needed, but the versions don't have to be pinned since it uses the local env
# go figure.
- atoml
- attrs
- click
- coloredlogs
- desert
- discord.py
- marshmallow
- python-dotenv
- pyyaml

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
rev: v4.2.0
hooks:
- id: check-case-conflict
- id: check-added-large-files
Expand All @@ -11,6 +33,7 @@ repos:
- id: check-yaml
exclude: 'mkdocs.yml' # Exclude all mkdocs.yml as they use tags i.e. `!!!`
- id: pretty-format-json
Shivansh-007 marked this conversation as resolved.
Show resolved Hide resolved
exclude: 'app.json'
args: [--indent=4, --autofix]
- id: end-of-file-fixer
- id: no-commit-to-branch
Expand Down Expand Up @@ -42,19 +65,19 @@ repos:
- id: python-use-type-annotations

- repo: https://github.com/PyCQA/isort
rev: 5.9.3
rev: 5.10.1
hooks:
- id: isort

- repo: https://github.com/asottile/blacken-docs
rev: v1.11.0
rev: v1.12.1
hooks:
- id: blacken-docs
additional_dependencies:
- black

- repo: https://github.com/psf/black
rev: 21.8b0
rev: 22.3.0
hooks:
- id: black
language_version: python3
Expand Down
9 changes: 7 additions & 2 deletions app.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
{
"env": {
"TOKEN": {
"description": "Discord bot token. This is from https://discord.com/developers/applications",
"MODMAIL_BOT_TOKEN": {
"description": "Discord bot token. Required to log in to discord.\nThis is obtainable from https://discord.com/developers/applications",
"required": true
},
"MODMAIL_BOT_PREFIX": {
"description": "Command prefix.",
"required": false,
"value": "?"
}
},
"name": "Modmail Bot",
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added Dispatcher system, although it is not hooked into important features like thread creation yet. (#71)
- Officially support python 3.10 (#119)
- Officially support windows and macos (#121)
- Completely rewrote configuration system (#75)

### Changed

Expand Down
27 changes: 22 additions & 5 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,14 @@ $ poetry install

### Set up modmail config

1. Create a copy of `config-default.yml` named `config.yml` in the the `modmail/` directory.
1. Create a copy of `modmail/default_config.toml` named `modmail_config.toml` in the root of the repository.

=== "Linux, macOS"

<div class="termy">

```console
$ cp -v modmail/config-default.toml modmail/config.toml
$ cp -v modmail/default_config.toml modmail_config.toml
```

</div>
Expand All @@ -169,20 +169,37 @@ $ poetry install
<div class="termy">

```console
$ xcopy /f modmail/config-default.toml modmail/config.toml
$ xcopy /f modmail/default_config.toml modmail_config.toml
```

</div>

!!! note
If you would like, there is optional support for yaml configuration. Make sure that pyyaml is installed with `poetry install --extras yaml`,
and copy modmail/defaults_config.yaml to modmail_config.yaml.

2. Set the modmail bot prefix in `bot.prefix`.
3. In case you are a contributor set `dev.mode.plugin_dev` and `dev.mode.develop` to `true`. The `develop` variable enables the developer bot extensions and `plugin_dev` enables plugin-developer friendly bot extensions.
4. Create a text file named `.env` in your project root (that's the base folder of your repository):
- You can also copy the `.env.template` file to `.env`
- You can also copy the `template.env` file to `.env`

!!!note
The entire file name is literally `.env`

5. Open the file with any text editor and write the bot token to the files in this format: `TOKEN="my_token"`.
5. Open the file with any text editor and write the bot token to the files in this format: `MODMAIL_BOT_TOKEN="my_token"`.


Of the several supported configuration sources, they are loaded in a specific priority. In decreasing priority:
- `os.environ`
- .env
- modmail_config.yaml (if PyYaml is installed and the file exists)
- modmail_config.toml (if the above file does not exist)
- defaults

Internally, the actual parsing order may not match the above,
but the end configuration object will have the above priorty.



### Run The Project

Expand Down
13 changes: 10 additions & 3 deletions modmail/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@

import coloredlogs

from modmail.log import ModmailLogger
from modmail.log import ModmailLogger, get_log_level_from_name


try:
import dotenv
except ModuleNotFoundError:
pass
else:
dotenv.load_dotenv(".env")

# On windows aiodns's asyncio support relies on APIs like add_reader (which aiodns uses)
# are not guaranteed to be available, and in particular are not available when using the
# ProactorEventLoop on Windows, this method is only supported with Windows SelectorEventLoop
Expand All @@ -21,11 +28,11 @@
logging.addLevelName(logging.NOTICE, "NOTICE")


LOG_FILE_SIZE = 8 * (2 ** 10) ** 2 # 8MB, discord upload limit
LOG_FILE_SIZE = 8 * (2**10) ** 2 # 8MB, discord upload limit

# this logging level is set to logging.TRACE because if it is not set to the lowest level,
# the child level will be limited to the lowest level this is set to.
ROOT_LOG_LEVEL = logging.TRACE
ROOT_LOG_LEVEL = get_log_level_from_name(os.environ.get("MODMAIL_LOG_LEVEL", logging.TRACE))
FMT = "%(asctime)s %(levelname)10s %(name)15s - [%(lineno)5d]: %(message)s"
DATEFMT = "%Y/%m/%d %H:%M:%S"

Expand Down
2 changes: 1 addition & 1 deletion modmail/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def main() -> None:
"""Run the bot."""
patch_embed()
bot = ModmailBot()
bot.run(bot.config.bot.token)
bot.run(bot.config.user.bot.token)


if __name__ == "__main__":
Expand Down
15 changes: 12 additions & 3 deletions modmail/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from discord.client import _cleanup_loop
from discord.ext import commands

from modmail.config import CONFIG
from modmail.config import config
from modmail.dispatcher import Dispatcher
from modmail.log import ModmailLogger
from modmail.utils.extensions import EXTENSIONS, NO_UNLOAD, walk_extensions
Expand Down Expand Up @@ -39,7 +39,7 @@ class ModmailBot(commands.Bot):
dispatcher: Dispatcher

def __init__(self, **kwargs):
self.config = CONFIG
self.config = config()
self.start_time: t.Optional[arrow.Arrow] = None # arrow.utcnow()
self.http_session: t.Optional[aiohttp.ClientSession] = None
self.dispatcher = Dispatcher()
Expand All @@ -51,7 +51,7 @@ def __init__(self, **kwargs):
activity = Activity(type=discord.ActivityType.listening, name="users dming me!")
# listen to messages mentioning the bot or matching the prefix
# ! NOTE: This needs to use the configuration system to get the prefix from the db once it exists.
prefix = commands.when_mentioned_or(CONFIG.bot.prefix)
prefix = self.determine_prefix
# allow only user mentions by default.
# ! NOTE: This may change in the future to allow roles as well
allowed_mentions = AllowedMentions(everyone=False, users=True, roles=False, replied_user=True)
Expand All @@ -68,6 +68,15 @@ def __init__(self, **kwargs):
**kwargs,
)

@staticmethod
async def determine_prefix(bot: "ModmailBot", message: discord.Message) -> t.List[str]:
"""Dynamically get the updated prefix on every command."""
prefixes = []
if bot.config.user.bot.prefix_when_mentioned:
prefixes.extend(commands.when_mentioned(bot, message))
prefixes.append(bot.config.user.bot.prefix)
return prefixes

async def create_connectors(self, *args, **kwargs) -> None:
"""Re-create the connector and set up sessions before logging into Discord."""
# Use asyncio for DNS resolution instead of threads so threads aren't spammed.
Expand Down
10 changes: 0 additions & 10 deletions modmail/config-default.toml

This file was deleted.

Loading