Utilities and JSON Database support #51
@ -68,7 +68,6 @@ class VersionInfo(NamedTuple):
|
||||
releaselevel: Literal["alpha", "beta", "candidate", "final"]
|
||||
serial: int
|
||||
|
||||
|
||||
version_info: VersionInfo = VersionInfo(major=2, minor=0, micro=0, releaselevel='alpha', serial=0)
|
||||
|
||||
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
||||
|
@ -83,6 +83,24 @@ class Colour:
|
||||
raise TypeError(f'Expected int parameter, received {value.__class__.__name__} instead.')
|
||||
|
||||
self.value: int = value
|
||||
|
||||
@staticmethod
|
||||
def from_base(self, value: str, base:int = None):
|
||||
"""
|
||||
Initiate self.value from different base(hexidecimal, binary)
|
||||
=======
|
||||
|
||||
value `str` :
|
||||
|
||||
value in different base, e.g. white in hexidecimal, 0xffffff
|
||||
|
||||
base `int` (optional) :
|
||||
|
||||
base of your value, if you don't supply this, you have to add a prefix to your number, e.g. 0x or 0b
|
||||
|
||||
"""
|
||||
|
||||
return Colour(value = int(value, base=base))
|
||||
|
||||
def _get_byte(self, byte: int) -> int:
|
||||
return (self.value >> (8 * byte)) & 0xff
|
||||
|
@ -315,13 +315,28 @@ class Embed:
|
||||
return getattr(self, '_colour', EmptyEmbed)
|
||||
|
||||
@colour.setter
|
||||
def colour(self, value: Union[int, Colour, _EmptyEmbed]): # type: ignore
|
||||
def colour(self, value: Union[int, Colour, _EmptyEmbed, str], base:int=None): # type: ignore
|
||||
"""
|
||||
Set colour
|
||||
============
|
||||
|
||||
value `Union[int, Colour, _EmptyEmbed, str]`:
|
||||
|
||||
value of the colour. If you want to use different number systems such as hexidecimal or binary, use Colour.from_base or set it as a string in that system
|
||||
|
||||
base `int` (optional):
|
||||
|
||||
if value is a string without a prefix(0x, 0b), set base here
|
||||
"""
|
||||
|
||||
if isinstance(value, (Colour, _EmptyEmbed)):
|
||||
self._colour = value
|
||||
elif isinstance(value, int):
|
||||
self._colour = Colour(value=value)
|
||||
elif isinstance(value, str):
|
||||
self._colour = int(value, base=base)
|
||||
else:
|
||||
raise TypeError(f'Expected discord.Colour, int, or Embed.Empty but received {value.__class__.__name__} instead.')
|
||||
raise TypeError(f'Expected discord.Colour, int, str, or Embed.Empty but received {value.__class__.__name__} instead.')
|
||||
|
||||
color = colour
|
||||
|
||||
|
@ -143,7 +143,7 @@ class HTTPException(DiscordException):
|
||||
self.code = 0
|
||||
|
||||
fmt = '{0.status} {0.reason} (error code: {1})'
|
||||
if len(self.text):
|
||||
if self.text:
|
||||
fmt += ': {2}'
|
||||
|
||||
super().__init__(fmt.format(self.response, self.code, self.text))
|
||||
|
@ -208,7 +208,7 @@ class Cog(metaclass=CogMeta):
|
||||
for command in self.__cog_commands__:
|
||||
setattr(self, command.callback.__name__, command)
|
||||
parent = command.parent
|
||||
if parent is not None:
|
||||
if parent:
|
||||
# Get the latest parent reference
|
||||
parent = lookup[parent.qualified_name] # type: ignore
|
||||
|
||||
@ -230,7 +230,7 @@ class Cog(metaclass=CogMeta):
|
||||
|
||||
This does not include subcommands.
|
||||
"""
|
||||
return [c for c in self.__cog_commands__ if c.parent is None]
|
||||
return [c for c in self.__cog_commands__ if not c.parent]
|
||||
|
||||
@property
|
||||
def qualified_name(self) -> str:
|
||||
|
@ -110,7 +110,7 @@ class CommandError(DiscordException):
|
||||
from :class:`.Bot`\, :func:`.on_command_error`.
|
||||
"""
|
||||
def __init__(self, message: Optional[str] = None, *args: Any) -> None:
|
||||
if message is not None:
|
||||
if message: # replace 'if not none' with 'if message'
|
||||
# clean-up @everyone and @here mentions
|
||||
m = message.replace('@everyone', '@\u200beveryone').replace('@here', '@\u200bhere')
|
||||
super().__init__(m, *args)
|
||||
|
0
discord/ext/json/__init__.py
Normal file
0
discord/ext/json/__init__.py
Normal file
50
discord/ext/json/database.py
Normal file
50
discord/ext/json/database.py
Normal file
@ -0,0 +1,50 @@
|
||||
from .types import JSONFile, Entry
|
||||
from typing import Union, Any
|
||||
|
||||
class Database:
|
||||
def __init__(self, file:JSONFile):
|
||||
self.file = file;
|
||||
self.database = {};
|
||||
|
||||
async def getData(self) -> dict:
|
||||
"""
|
||||
Get contents from a JSONFile
|
||||
"""
|
||||
|
||||
contents = await self.file.serialize("load")
|
||||
|
||||
return contents
|
||||
|
||||
async def dumpData(self, data:dict) -> None:
|
||||
"""
|
||||
Dump a dict into file
|
||||
=====
|
||||
|
||||
data `dict` -
|
||||
|
||||
The data to be dumped into the file.
|
||||
"""
|
||||
|
||||
await self.file.serialize("dump", contents=data)
|
||||
|
||||
async def loadFile(self) -> None:
|
||||
"""
|
||||
Load JSON from file to self.database
|
||||
"""
|
||||
|
||||
self.database = await self.getData();
|
||||
|
||||
async def getEntry(self, name:str) -> Entry:
|
||||
value : Union[Any] = self.database[name]
|
||||
|
||||
return Entry(name, value)
|
||||
|
||||
async def editEntry(self, name:str, value:Union[Any]):
|
||||
self.database[name] = value;
|
||||
|
||||
async def saveData(self):
|
||||
"""
|
||||
Save current database to file
|
||||
"""
|
||||
|
||||
await self.file.serialize("dump", contents=self.database)
|
137
discord/ext/json/types.py
Normal file
137
discord/ext/json/types.py
Normal file
@ -0,0 +1,137 @@
|
||||
import json
|
||||
|
||||
from typing import Union, Any
|
||||
|
||||
|
||||
class File:
|
||||
def __init__(self, path:str):
|
||||
"""
|
||||
Initialize a file.
|
||||
|
||||
=======
|
||||
|
||||
path `str` :
|
||||
|
||||
path to the file
|
||||
"""
|
||||
|
||||
self.path : str = path
|
||||
|
||||
@staticmethod
|
||||
def construct(path:str):
|
||||
"""
|
||||
Construct a File object statically
|
||||
"""
|
||||
|
||||
if not isinstance(path, str):
|
||||
raise TypeError(f"Expected path to be type str, got {type(path)} instead.")
|
||||
|
||||
return File(path)
|
||||
|
||||
async def access(self, mode:str):
|
||||
"""
|
||||
Open object to access file. Don't use this in your code.
|
||||
"""
|
||||
|
||||
if not isinstance(mode, str):
|
||||
raise TypeError(f"Expected mode to be type str, got {type(mode)} instead.")
|
||||
|
||||
return open(self.path, mode)
|
||||
|
||||
async def open_writer(self):
|
||||
"""Open plain writer for file"""
|
||||
|
||||
return await self.access("w+")
|
||||
|
||||
async def open_reader(self):
|
||||
"""Open plain reader for file"""
|
||||
|
||||
return await self.access("r+")
|
||||
|
||||
async def open_binary_writer(self):
|
||||
"""Open binary writer for file"""
|
||||
|
||||
return await self.access("wb+")
|
||||
|
||||
async def open_binary_reader(self):
|
||||
"""Open binary reader for file"""
|
||||
|
||||
return await self.access("rb+")
|
||||
|
||||
async def read_contents(self, binary=False) -> Union[str, bytes]:
|
||||
"""
|
||||
Dump out file contents
|
||||
======
|
||||
|
||||
binary `bool` (optional):
|
||||
|
||||
Set to False normally. Controls whether to read file as binary or read as normal text.
|
||||
"""
|
||||
|
||||
reader = None # initialize
|
||||
|
||||
if binary:
|
||||
reader = await self.open_binary_reader()
|
||||
else:
|
||||
reader = await self.open_reader()
|
||||
|
||||
contents = reader.read()
|
||||
|
||||
reader.close() # safely close file
|
||||
|
||||
return contents
|
||||
|
||||
async def serialize(self, serializer, *args, **kwargs) -> Union[Any]:#
|
||||
return serializer(*args, **kwargs)
|
||||
|
||||
class JSONFile(File):
|
||||
load = json.load
|
||||
dump = json.dump
|
||||
|
||||
async def serialize(self, serializer:str, *args, **kwargs) -> Union[dict, int]:
|
||||
"""
|
||||
Serialize JSON data
|
||||
=====
|
||||
|
||||
serializer `str`:
|
||||
|
||||
dump or load data, set to "load" for loading file, "dump" to dump json to file
|
||||
|
||||
contents `dict` of kwargs:
|
||||
|
||||
what to dump.
|
||||
"""
|
||||
|
||||
if not serializer:
|
||||
raise ValueError("Argument serializer should be either load or dump, got NoneType instead.")
|
||||
|
||||
if serializer == "load":
|
||||
reader = self.open_reader()
|
||||
contents = JSONFile.load(reader)
|
||||
reader.close()
|
||||
|
||||
return contents
|
||||
elif serializer == "dump":
|
||||
writer = self.open_writer()
|
||||
|
||||
JSONFile.dump(kwargs["contents"], writer)
|
||||
|
||||
writer.close()
|
||||
|
||||
return 0;
|
||||
|
||||
class Entry:
|
||||
"""
|
||||
Class representing a JSON Entry
|
||||
"""
|
||||
|
||||
def __init__(self, name:str, value:Union[Any]):
|
||||
self.name : str = name;
|
||||
self.value : Union[Any] = value;
|
||||
|
||||
async def browse(self, name:str):
|
||||
"""
|
||||
Browse entry and get a new Entry object if it finds something successfully
|
||||
"""
|
||||
|
||||
return Entry(name, self.value[name])
|
@ -60,6 +60,8 @@ import re
|
||||
import sys
|
||||
import types
|
||||
import warnings
|
||||
from .embeds import Embed
|
||||
from .colors import Colour
|
||||
|
||||
from .errors import InvalidArgument
|
||||
|
||||
@ -168,6 +170,41 @@ class CachedSlotProperty(Generic[T, T_co]):
|
||||
setattr(instance, self.name, value)
|
||||
return value
|
||||
|
||||
def generate_embed(header:str, content:str, footer:str, color=None): # Courtesy of Dank HadocK, my friend who coded this for my rewrite.
|
||||
"""
|
||||
Easy way to form embeds
|
||||
|
||||
This was made by Dank Had0cK, a valuable contributor on my fork. Thanks.
|
||||
|
||||
=====
|
||||
|
||||
header `str`:
|
||||
|
||||
Header of your embed
|
||||
|
||||
content `str`:
|
||||
|
||||
Content of your embed
|
||||
|
||||
footer `str`:
|
||||
|
||||
Footer of your embed
|
||||
|
||||
color `str` optional:
|
||||
|
||||
If it is None, color will default to 2F3136
|
||||
Hexstring of your color, uses color converter by Arkae to convert hex to int.
|
||||
"""
|
||||
|
||||
embed = Embed()
|
||||
embed.title = header
|
||||
embed.description = content
|
||||
if color is None:
|
||||
embed.color = Colour.from_base("0x2f3136")
|
||||
else:
|
||||
embed.color = Colour.from_base(color, 16)
|
||||
embed.set_footer(text=footer)
|
||||
return embed
|
||||
|
||||
class classproperty(Generic[T_co]):
|
||||
def __init__(self, fget: Callable[[Any], T_co]) -> None:
|
||||
|
Loading…
x
Reference in New Issue
Block a user