mirror of
https://github.com/pyrogram/pyrogram
synced 2025-08-31 06:16:06 +00:00
Deep rewrite: preparing for v1.0
- Pyrogram core is now fully asynchronous - Ditched Python 3.5, welcome 3.6 as minimum version. - Moved all types to pyrogram.types - Turned the Filters class into a module (filters) - Moved all filters to pyrogram.filters - Moved all handlers to pyrogram.handlers - Moved all emoji to pyrogram.emoji - Renamed pyrogram.api to pyrogram.raw - Clock is now synced with server's time - Telegram schema updated to Layer 117 - Greatly improved the TL compiler (proper type-constructor hierarchy) - Added "do not edit" warning in generated files - Crypto parts are executed in a thread pool to avoid blocking the event loop - idle() is now a separate function (it doesn't deal with Client instances) - Async storage, async filters and async progress callback (optional, can be sync too) - Added getpass back, for hidden password inputs
This commit is contained in:
@@ -19,142 +19,110 @@
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from typing import NamedTuple, List, Tuple
|
||||
|
||||
HOME = "compiler/api"
|
||||
DESTINATION = "pyrogram/api"
|
||||
# from autoflake import fix_code
|
||||
# from black import format_str, FileMode
|
||||
|
||||
HOME_PATH = Path("compiler/api")
|
||||
DESTINATION_PATH = Path("pyrogram/raw")
|
||||
NOTICE_PATH = "NOTICE"
|
||||
|
||||
SECTION_RE = re.compile(r"---(\w+)---")
|
||||
LAYER_RE = re.compile(r"//\sLAYER\s(\d+)")
|
||||
COMBINATOR_RE = re.compile(r"^([\w.]+)#([0-9a-f]+)\s(?:.*)=\s([\w<>.]+);(?: // Docs: (.+))?$", re.MULTILINE)
|
||||
COMBINATOR_RE = re.compile(r"^([\w.]+)#([0-9a-f]+)\s(?:.*)=\s([\w<>.]+);$", re.MULTILINE)
|
||||
ARGS_RE = re.compile(r"[^{](\w+):([\w?!.<>#]+)")
|
||||
FLAGS_RE = re.compile(r"flags\.(\d+)\?")
|
||||
FLAGS_RE_2 = re.compile(r"flags\.(\d+)\?([\w<>.]+)")
|
||||
FLAGS_RE_3 = re.compile(r"flags:#")
|
||||
INT_RE = re.compile(r"int(\d+)")
|
||||
|
||||
core_types = ["int", "long", "int128", "int256", "double", "bytes", "string", "Bool"]
|
||||
CORE_TYPES = ["int", "long", "int128", "int256", "double", "bytes", "string", "Bool", "true"]
|
||||
|
||||
WARNING = """
|
||||
# # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# !!! WARNING !!! #
|
||||
# This is a generated file! #
|
||||
# All changes made in this file will be lost! #
|
||||
# # # # # # # # # # # # # # # # # # # # # # # #
|
||||
""".strip()
|
||||
|
||||
# noinspection PyShadowingBuiltins
|
||||
open = partial(open, encoding="utf-8")
|
||||
|
||||
types_to_constructors = {}
|
||||
types_to_functions = {}
|
||||
constructors_to_functions = {}
|
||||
namespaces_to_types = {}
|
||||
namespaces_to_constructors = {}
|
||||
namespaces_to_functions = {}
|
||||
|
||||
|
||||
def get_docstring_arg_type(t: str, is_list: bool = False, is_pyrogram_type: bool = False):
|
||||
if t in core_types:
|
||||
if t == "long":
|
||||
return "``int`` ``64-bit``"
|
||||
elif "int" in t:
|
||||
size = INT_RE.match(t)
|
||||
return "``int`` ``{}-bit``".format(size.group(1)) if size else "``int`` ``32-bit``"
|
||||
elif t == "double":
|
||||
return "``float`` ``64-bit``"
|
||||
elif t == "string":
|
||||
return "``str``"
|
||||
else:
|
||||
return "``{}``".format(t.lower())
|
||||
elif t == "true":
|
||||
return "``bool``"
|
||||
elif t == "TLObject" or t == "X":
|
||||
return "Any object from :obj:`~pyrogram.api.types`"
|
||||
elif t == "!X":
|
||||
return "Any method from :obj:`~pyrogram.api.functions`"
|
||||
elif t.startswith("Vector"):
|
||||
return "List of " + get_docstring_arg_type(t.split("<", 1)[1][:-1], True, is_pyrogram_type)
|
||||
else:
|
||||
if is_pyrogram_type:
|
||||
t = "pyrogram." + t
|
||||
|
||||
t = types_to_constructors.get(t, [t])
|
||||
n = len(t) - 1
|
||||
|
||||
t = (("e" if is_list else "E") + "ither " if n else "") + ", ".join(
|
||||
":obj:`{1} <{0}.{1}>`".format(
|
||||
"pyrogram.types" if is_pyrogram_type else "pyrogram.api.types",
|
||||
i.replace("pyrogram.", "")
|
||||
)
|
||||
for i in t
|
||||
)
|
||||
|
||||
if n:
|
||||
t = t.split(", ")
|
||||
t = ", ".join(t[:-1]) + " or " + t[-1]
|
||||
|
||||
return t
|
||||
class Combinator(NamedTuple):
|
||||
section: str
|
||||
qualname: str
|
||||
namespace: str
|
||||
name: str
|
||||
id: str
|
||||
has_flags: bool
|
||||
args: List[Tuple[str, str]]
|
||||
qualtype: str
|
||||
typespace: str
|
||||
type: str
|
||||
|
||||
|
||||
def get_references(t: str):
|
||||
t = constructors_to_functions.get(t)
|
||||
|
||||
if t:
|
||||
n = len(t) - 1
|
||||
|
||||
t = ", ".join(
|
||||
":obj:`{0} <pyrogram.api.functions.{0}>`".format(i)
|
||||
for i in t
|
||||
)
|
||||
|
||||
if n:
|
||||
t = t.split(", ")
|
||||
t = ", ".join(t[:-1]) + " and " + t[-1]
|
||||
|
||||
return t
|
||||
|
||||
|
||||
def get_argument_type(arg):
|
||||
is_flag = FLAGS_RE.match(arg[1])
|
||||
name, t = arg
|
||||
|
||||
if is_flag:
|
||||
t = t.split("?")[1]
|
||||
|
||||
if t in core_types:
|
||||
if t == "long" or "int" in t:
|
||||
t = ": int"
|
||||
elif t == "double":
|
||||
t = ": float"
|
||||
elif t == "string":
|
||||
t = ": str"
|
||||
else:
|
||||
t = ": {}".format(t.lower())
|
||||
elif t == "true":
|
||||
t = ": bool"
|
||||
elif t.startswith("Vector"):
|
||||
t = ": list"
|
||||
else:
|
||||
return name + ("=None" if is_flag else "")
|
||||
|
||||
return name + t + (" = None" if is_flag else "")
|
||||
|
||||
|
||||
class Combinator:
|
||||
def __init__(self,
|
||||
section: str,
|
||||
namespace: str,
|
||||
name: str,
|
||||
id: str,
|
||||
args: list,
|
||||
has_flags: bool,
|
||||
return_type: str,
|
||||
docs: str):
|
||||
self.section = section
|
||||
self.namespace = namespace
|
||||
self.name = name
|
||||
self.id = id
|
||||
self.args = args
|
||||
self.has_flags = has_flags
|
||||
self.return_type = return_type
|
||||
self.docs = docs
|
||||
|
||||
|
||||
def snek(s: str):
|
||||
# https://stackoverflow.com/questions/1175208/elegant-python-function-to-convert-camelcase-to-snake-case
|
||||
def snake(s: str):
|
||||
# https://stackoverflow.com/q/1175208
|
||||
s = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", s)
|
||||
return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s).lower()
|
||||
|
||||
|
||||
def capit(s: str):
|
||||
def camel(s: str):
|
||||
return "".join([i[0].upper() + i[1:] for i in s.split("_")])
|
||||
|
||||
|
||||
# noinspection PyShadowingBuiltins, PyShadowingNames
|
||||
def get_type_hint(type: str) -> str:
|
||||
is_flag = FLAGS_RE.match(type)
|
||||
is_core = False
|
||||
|
||||
if is_flag:
|
||||
type = type.split("?")[1]
|
||||
|
||||
if type in CORE_TYPES:
|
||||
is_core = True
|
||||
|
||||
if type == "long" or "int" in type:
|
||||
type = "int"
|
||||
elif type == "double":
|
||||
type = "float"
|
||||
elif type == "string":
|
||||
type = "str"
|
||||
elif type in ["Bool", "true"]:
|
||||
type = "bool"
|
||||
else: # bytes and object
|
||||
type = "bytes"
|
||||
|
||||
if type in ["Object", "!X"]:
|
||||
return "TLObject"
|
||||
|
||||
if re.match("^vector", type, re.I):
|
||||
is_core = True
|
||||
|
||||
sub_type = type.split("<")[1][:-1]
|
||||
type = f"List[{get_type_hint(sub_type)}]"
|
||||
|
||||
if is_core:
|
||||
return f"Union[None, {type}] = None" if is_flag else type
|
||||
else:
|
||||
ns, name = type.split(".") if "." in type else ("", type)
|
||||
type = f'"raw.base.' + ".".join([ns, name]).strip(".") + '"'
|
||||
|
||||
return f'{type}{" = None" if is_flag else ""}'
|
||||
|
||||
|
||||
def sort_args(args):
|
||||
"""Put flags at the end"""
|
||||
args = args.copy()
|
||||
@@ -163,99 +131,167 @@ def sort_args(args):
|
||||
for i in flags:
|
||||
args.remove(i)
|
||||
|
||||
try:
|
||||
args.remove(("flags", "#"))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return args + flags
|
||||
|
||||
|
||||
def start():
|
||||
shutil.rmtree("{}/types".format(DESTINATION), ignore_errors=True)
|
||||
shutil.rmtree("{}/functions".format(DESTINATION), ignore_errors=True)
|
||||
def remove_whitespaces(source: str) -> str:
|
||||
"""Remove whitespaces from blank lines"""
|
||||
lines = source.split("\n")
|
||||
|
||||
with open("{}/source/auth_key.tl".format(HOME), encoding="utf-8") as auth, \
|
||||
open("{}/source/sys_msgs.tl".format(HOME), encoding="utf-8") as system, \
|
||||
open("{}/source/main_api.tl".format(HOME), encoding="utf-8") as api:
|
||||
schema = (auth.read() + system.read() + api.read()).splitlines()
|
||||
for i, _ in enumerate(lines):
|
||||
if re.match(r"^\s+$", lines[i]):
|
||||
lines[i] = ""
|
||||
|
||||
with open("{}/template/mtproto.txt".format(HOME), encoding="utf-8") as f:
|
||||
mtproto_template = f.read()
|
||||
return "\n".join(lines)
|
||||
|
||||
with open("{}/template/pyrogram.txt".format(HOME), encoding="utf-8") as f:
|
||||
pyrogram_template = f.read()
|
||||
|
||||
def get_docstring_arg_type(t: str, is_list: bool = False, is_pyrogram_type: bool = False):
|
||||
if t in CORE_TYPES:
|
||||
if t == "long":
|
||||
return "``int`` ``64-bit``"
|
||||
elif "int" in t:
|
||||
size = INT_RE.match(t)
|
||||
return f"``int`` ``{size.group(1)}-bit``" if size else "``int`` ``32-bit``"
|
||||
elif t == "double":
|
||||
return "``float`` ``64-bit``"
|
||||
elif t == "string":
|
||||
return "``str``"
|
||||
elif t == "true":
|
||||
return "``bool``"
|
||||
else:
|
||||
return f"``{t.lower()}``"
|
||||
elif t == "TLObject" or t == "X":
|
||||
return "Any object from :obj:`~pyrogram.raw.types`"
|
||||
elif t == "!X":
|
||||
return "Any method from :obj:`~pyrogram.raw.functions`"
|
||||
elif t.lower().startswith("vector"):
|
||||
return "List of " + get_docstring_arg_type(t.split("<", 1)[1][:-1], True)
|
||||
else:
|
||||
return f":obj:`{t} <pyrogram.raw.base.{t}>`"
|
||||
|
||||
|
||||
def get_references(t: str, kind: str):
|
||||
if kind == "constructors":
|
||||
t = constructors_to_functions.get(t)
|
||||
elif kind == "types":
|
||||
t = types_to_functions.get(t)
|
||||
else:
|
||||
raise ValueError("Invalid kind")
|
||||
|
||||
if t:
|
||||
return "\n ".join(
|
||||
f"- :obj:`{i} <pyrogram.raw.functions.{i}>`"
|
||||
for i in t
|
||||
), len(t)
|
||||
|
||||
return None, 0
|
||||
|
||||
|
||||
# noinspection PyShadowingBuiltins
|
||||
def start(format: bool = False):
|
||||
shutil.rmtree(DESTINATION_PATH / "types", ignore_errors=True)
|
||||
shutil.rmtree(DESTINATION_PATH / "functions", ignore_errors=True)
|
||||
shutil.rmtree(DESTINATION_PATH / "base", ignore_errors=True)
|
||||
|
||||
with open(HOME_PATH / "source/auth_key.tl") as f1, \
|
||||
open(HOME_PATH / "source/sys_msgs.tl") as f2, \
|
||||
open(HOME_PATH / "source/main_api.tl") as f3:
|
||||
schema = (f1.read() + f2.read() + f3.read()).splitlines()
|
||||
|
||||
with open(HOME_PATH / "template/type.txt") as f1, \
|
||||
open(HOME_PATH / "template/combinator.txt") as f2:
|
||||
type_tmpl = f1.read()
|
||||
combinator_tmpl = f2.read()
|
||||
|
||||
with open(NOTICE_PATH, encoding="utf-8") as f:
|
||||
notice = []
|
||||
|
||||
for line in f.readlines():
|
||||
notice.append("# {}".format(line).strip())
|
||||
notice.append(f"# {line}".strip())
|
||||
|
||||
notice = "\n".join(notice)
|
||||
|
||||
section = None
|
||||
layer = None
|
||||
namespaces = {"types": set(), "functions": set()}
|
||||
combinators = []
|
||||
|
||||
for line in schema:
|
||||
# Check for section changer lines
|
||||
s = SECTION_RE.match(line)
|
||||
if s:
|
||||
section = s.group(1)
|
||||
section_match = SECTION_RE.match(line)
|
||||
if section_match:
|
||||
section = section_match.group(1)
|
||||
continue
|
||||
|
||||
# Save the layer version
|
||||
l = LAYER_RE.match(line)
|
||||
if l:
|
||||
layer = l.group(1)
|
||||
layer_match = LAYER_RE.match(line)
|
||||
if layer_match:
|
||||
layer = layer_match.group(1)
|
||||
continue
|
||||
|
||||
combinator = COMBINATOR_RE.match(line)
|
||||
if combinator:
|
||||
name, id, return_type, docs = combinator.groups()
|
||||
namespace, name = name.split(".") if "." in name else ("", name)
|
||||
args = ARGS_RE.findall(line.split(" //")[0])
|
||||
combinator_match = COMBINATOR_RE.match(line)
|
||||
if combinator_match:
|
||||
# noinspection PyShadowingBuiltins
|
||||
qualname, id, qualtype = combinator_match.groups()
|
||||
|
||||
namespace, name = qualname.split(".") if "." in qualname else ("", qualname)
|
||||
name = camel(name)
|
||||
qualname = ".".join([namespace, name]).lstrip(".")
|
||||
|
||||
typespace, type = qualtype.split(".") if "." in qualtype else ("", qualtype)
|
||||
type = camel(type)
|
||||
qualtype = ".".join([typespace, type]).lstrip(".")
|
||||
|
||||
# Pingu!
|
||||
has_flags = not not FLAGS_RE_3.findall(line)
|
||||
|
||||
# Fix file and folder name collision
|
||||
if name == "updates":
|
||||
name = "update"
|
||||
args = ARGS_RE.findall(line)
|
||||
|
||||
# Fix arg name being "self" (reserved keyword)
|
||||
# Fix arg name being "self" (reserved python keyword)
|
||||
for i, item in enumerate(args):
|
||||
if item[0] == "self":
|
||||
args[i] = ("is_self", item[1])
|
||||
|
||||
if namespace:
|
||||
namespaces[section].add(namespace)
|
||||
|
||||
combinators.append(
|
||||
Combinator(
|
||||
section,
|
||||
namespace,
|
||||
capit(name),
|
||||
"0x{}".format(id.zfill(8)),
|
||||
args,
|
||||
has_flags,
|
||||
".".join(
|
||||
return_type.split(".")[:-1]
|
||||
+ [capit(return_type.split(".")[-1])]
|
||||
),
|
||||
docs
|
||||
)
|
||||
combinator = Combinator(
|
||||
section=section,
|
||||
qualname=qualname,
|
||||
namespace=namespace,
|
||||
name=name,
|
||||
id=f"0x{id}",
|
||||
has_flags=has_flags,
|
||||
args=args,
|
||||
qualtype=qualtype,
|
||||
typespace=typespace,
|
||||
type=type
|
||||
)
|
||||
|
||||
for c in combinators:
|
||||
return_type = c.return_type
|
||||
combinators.append(combinator)
|
||||
|
||||
if return_type.startswith("Vector"):
|
||||
return_type = return_type.split("<")[1][:-1]
|
||||
for c in combinators:
|
||||
qualtype = c.qualtype
|
||||
|
||||
if qualtype.startswith("Vector"):
|
||||
qualtype = qualtype.split("<")[1][:-1]
|
||||
|
||||
d = types_to_constructors if c.section == "types" else types_to_functions
|
||||
|
||||
if return_type not in d:
|
||||
d[return_type] = []
|
||||
if qualtype not in d:
|
||||
d[qualtype] = []
|
||||
|
||||
d[return_type].append(".".join(filter(None, [c.namespace, c.name])))
|
||||
d[qualtype].append(c.qualname)
|
||||
|
||||
if c.section == "types":
|
||||
key = c.namespace
|
||||
|
||||
if key not in namespaces_to_types:
|
||||
namespaces_to_types[key] = []
|
||||
|
||||
if c.type not in namespaces_to_types[key]:
|
||||
namespaces_to_types[key].append(c.type)
|
||||
|
||||
for k, v in types_to_constructors.items():
|
||||
for i in v:
|
||||
@@ -264,85 +300,100 @@ def start():
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
total = len(combinators)
|
||||
current = 0
|
||||
for c in combinators: # type: Combinator
|
||||
print("Compiling APIs... [{}%] {}".format(
|
||||
str(round(current * 100 / total)).rjust(3),
|
||||
".".join(filter(None, [c.section, c.namespace, c.name]))
|
||||
), end=" \r", flush=True)
|
||||
current += 1
|
||||
# import json
|
||||
# print(json.dumps(namespaces_to_types, indent=2))
|
||||
|
||||
path = "{}/{}/{}".format(DESTINATION, c.section, c.namespace)
|
||||
os.makedirs(path, exist_ok=True)
|
||||
for qualtype in types_to_constructors:
|
||||
typespace, type = qualtype.split(".") if "." in qualtype else ("", qualtype)
|
||||
dir_path = DESTINATION_PATH / "base" / typespace
|
||||
|
||||
init = "{}/__init__.py".format(path)
|
||||
module = type
|
||||
|
||||
if not os.path.exists(init):
|
||||
with open(init, "w", encoding="utf-8") as f:
|
||||
f.write(notice + "\n\n")
|
||||
if module == "Updates":
|
||||
module = "UpdatesT"
|
||||
|
||||
with open(init, "a", encoding="utf-8") as f:
|
||||
f.write("from .{} import {}\n".format(snek(c.name), capit(c.name)))
|
||||
os.makedirs(dir_path, exist_ok=True)
|
||||
|
||||
constructors = sorted(types_to_constructors[qualtype])
|
||||
constr_count = len(constructors)
|
||||
items = "\n ".join([f"- :obj:`{c} <pyrogram.raw.types.{c}>`" for c in constructors])
|
||||
|
||||
docstring = f"This base type has {constr_count} constructor{'s' if constr_count > 1 else ''} available.\n\n"
|
||||
docstring += f" Constructors:\n .. hlist::\n :columns: 2\n\n {items}"
|
||||
|
||||
references, ref_count = get_references(qualtype, "types")
|
||||
|
||||
if references:
|
||||
docstring += f"\n\n See Also:\n This object can be returned by " \
|
||||
f"{ref_count} method{'s' if ref_count > 1 else ''}:" \
|
||||
f"\n\n .. hlist::\n :columns: 2\n\n " + references
|
||||
|
||||
with open(dir_path / f"{snake(module)}.py", "w") as f:
|
||||
f.write(
|
||||
type_tmpl.format(
|
||||
notice=notice,
|
||||
warning=WARNING,
|
||||
docstring=docstring,
|
||||
name=type,
|
||||
qualname=qualtype,
|
||||
types=", ".join([f"raw.types.{c}" for c in constructors])
|
||||
)
|
||||
)
|
||||
|
||||
for c in combinators:
|
||||
sorted_args = sort_args(c.args)
|
||||
|
||||
arguments = (
|
||||
", "
|
||||
+ ("*, " if c.args else "")
|
||||
+ (", ".join([get_argument_type(i) for i in sorted_args if i != ("flags", "#")]) if c.args else "")
|
||||
(", *, " if c.args else "") +
|
||||
(", ".join(
|
||||
[f"{i[0]}: {get_type_hint(i[1])}"
|
||||
for i in sorted_args]
|
||||
) if sorted_args else "")
|
||||
)
|
||||
|
||||
fields = "\n ".join(
|
||||
["self.{0} = {0} # {1}".format(i[0], i[1]) for i in c.args if i != ("flags", "#")]
|
||||
) if c.args else "pass"
|
||||
[f"self.{i[0]} = {i[0]} # {i[1]}"
|
||||
for i in sorted_args]
|
||||
) if sorted_args else "pass"
|
||||
|
||||
docstring = ""
|
||||
docstring_args = []
|
||||
docs = c.docs.split("|")[1:] if c.docs else None
|
||||
|
||||
for i, arg in enumerate(sorted_args):
|
||||
if arg == ("flags", "#"):
|
||||
continue
|
||||
|
||||
arg_name, arg_type = arg
|
||||
is_optional = FLAGS_RE.match(arg_type)
|
||||
flag_number = is_optional.group(1) if is_optional else -1
|
||||
arg_type = arg_type.split("?")[-1]
|
||||
|
||||
if docs:
|
||||
docstring_args.append(
|
||||
"{} ({}{}):\n {}\n".format(
|
||||
arg_name,
|
||||
get_docstring_arg_type(arg_type, is_pyrogram_type=True),
|
||||
", optional" if "Optional" in docs[i] else "",
|
||||
re.sub("Optional\. ", "", docs[i].split("§")[1].rstrip(".") + ".")
|
||||
)
|
||||
)
|
||||
else:
|
||||
docstring_args.append(
|
||||
"{}{}: {}".format(
|
||||
arg_name,
|
||||
" (optional)".format(flag_number) if is_optional else "",
|
||||
get_docstring_arg_type(arg_type, is_pyrogram_type=c.namespace == "pyrogram")
|
||||
)
|
||||
docstring_args.append(
|
||||
"{}{}: {}".format(
|
||||
arg_name,
|
||||
" (optional)".format(flag_number) if is_optional else "",
|
||||
get_docstring_arg_type(arg_type, is_pyrogram_type=c.namespace == "pyrogram")
|
||||
)
|
||||
)
|
||||
|
||||
if c.section == "types":
|
||||
docstring += f"This object is a constructor of the base type :obj:`~pyrogram.raw.base.{c.qualtype}`.\n\n"
|
||||
else:
|
||||
docstring += f"Telegram API method.\n\n"
|
||||
|
||||
docstring += f" Details:\n - Layer: ``{layer}``\n - ID: ``{c.id}``\n\n"
|
||||
|
||||
if docstring_args:
|
||||
docstring_args = "Parameters:\n " + "\n ".join(docstring_args)
|
||||
docstring += " Parameters:\n " + "\n ".join(docstring_args)
|
||||
else:
|
||||
docstring_args = "No parameters required."
|
||||
|
||||
docstring_args = "Attributes:\n ID: ``{}``\n\n ".format(c.id) + docstring_args
|
||||
docstring_args = "Attributes:\n LAYER: ``{}``\n\n ".format(layer) + docstring_args
|
||||
docstring += " **No parameters required.**"
|
||||
|
||||
if c.section == "functions":
|
||||
docstring_args += "\n\n Returns:\n " + get_docstring_arg_type(c.return_type)
|
||||
|
||||
docstring += "\n\n Returns:\n " + get_docstring_arg_type(c.qualtype)
|
||||
else:
|
||||
references = get_references(".".join(filter(None, [c.namespace, c.name])))
|
||||
references, count = get_references(c.qualname, "constructors")
|
||||
|
||||
if references:
|
||||
docstring_args += "\n\n See Also:\n This object can be returned by " + references + "."
|
||||
docstring += f"\n\n See Also:\n This object can be returned by " \
|
||||
f"{count} method{'s' if count > 1 else ''}:" \
|
||||
f"\n\n .. hlist::\n :columns: 2\n\n " + references
|
||||
|
||||
write_types = read_types = "" if c.has_flags else "# No flags\n "
|
||||
|
||||
@@ -355,17 +406,16 @@ def start():
|
||||
for i in c.args:
|
||||
flag = FLAGS_RE.match(i[1])
|
||||
if flag:
|
||||
write_flags.append(
|
||||
"flags |= (1 << {}) if self.{} is not None else 0".format(flag.group(1), i[0]))
|
||||
write_flags.append(f"flags |= (1 << {flag.group(1)}) if self.{i[0]} is not None else 0")
|
||||
|
||||
write_flags = "\n ".join([
|
||||
"flags = 0",
|
||||
"\n ".join(write_flags),
|
||||
"b.write(Int(flags))\n "
|
||||
"data.write(Int(flags))\n "
|
||||
])
|
||||
|
||||
write_types += write_flags
|
||||
read_types += "flags = Int.read(b)\n "
|
||||
read_types += "flags = Int.read(data)\n "
|
||||
|
||||
continue
|
||||
|
||||
@@ -374,126 +424,171 @@ def start():
|
||||
|
||||
if flag_type == "true":
|
||||
read_types += "\n "
|
||||
read_types += "{} = True if flags & (1 << {}) else False".format(arg_name, index)
|
||||
elif flag_type in core_types:
|
||||
read_types += f"{arg_name} = True if flags & (1 << {index}) else False"
|
||||
elif flag_type in CORE_TYPES:
|
||||
write_types += "\n "
|
||||
write_types += "if self.{} is not None:\n ".format(arg_name)
|
||||
write_types += "b.write({}(self.{}))\n ".format(flag_type.title(), arg_name)
|
||||
write_types += f"if self.{arg_name} is not None:\n "
|
||||
write_types += f"data.write({flag_type.title()}(self.{arg_name}))\n "
|
||||
|
||||
read_types += "\n "
|
||||
read_types += "{} = {}.read(b) if flags & (1 << {}) else None".format(
|
||||
arg_name, flag_type.title(), index
|
||||
)
|
||||
read_types += f"{arg_name} = {flag_type.title()}.read(data) if flags & (1 << {index}) else None"
|
||||
elif "vector" in flag_type.lower():
|
||||
sub_type = arg_type.split("<")[1][:-1]
|
||||
|
||||
write_types += "\n "
|
||||
write_types += "if self.{} is not None:\n ".format(arg_name)
|
||||
write_types += "b.write(Vector(self.{}{}))\n ".format(
|
||||
arg_name, ", {}".format(sub_type.title()) if sub_type in core_types else ""
|
||||
write_types += f"if self.{arg_name} is not None:\n "
|
||||
write_types += "data.write(Vector(self.{}{}))\n ".format(
|
||||
arg_name, f", {sub_type.title()}" if sub_type in CORE_TYPES else ""
|
||||
)
|
||||
|
||||
read_types += "\n "
|
||||
read_types += "{} = TLObject.read(b{}) if flags & (1 << {}) else []\n ".format(
|
||||
arg_name, ", {}".format(sub_type.title()) if sub_type in core_types else "", index
|
||||
read_types += "{} = TLObject.read(data{}) if flags & (1 << {}) else []\n ".format(
|
||||
arg_name, f", {sub_type.title()}" if sub_type in CORE_TYPES else "", index
|
||||
)
|
||||
else:
|
||||
write_types += "\n "
|
||||
write_types += "if self.{} is not None:\n ".format(arg_name)
|
||||
write_types += "b.write(self.{}.write())\n ".format(arg_name)
|
||||
write_types += f"if self.{arg_name} is not None:\n "
|
||||
write_types += f"data.write(self.{arg_name}.write())\n "
|
||||
|
||||
read_types += "\n "
|
||||
read_types += "{} = TLObject.read(b) if flags & (1 << {}) else None\n ".format(
|
||||
arg_name, index
|
||||
)
|
||||
read_types += f"{arg_name} = TLObject.read(data) if flags & (1 << {index}) else None\n "
|
||||
else:
|
||||
if arg_type in core_types:
|
||||
if arg_type in CORE_TYPES:
|
||||
write_types += "\n "
|
||||
write_types += "b.write({}(self.{}))\n ".format(arg_type.title(), arg_name)
|
||||
write_types += f"data.write({arg_type.title()}(self.{arg_name}))\n "
|
||||
|
||||
read_types += "\n "
|
||||
read_types += "{} = {}.read(b)\n ".format(arg_name, arg_type.title())
|
||||
read_types += f"{arg_name} = {arg_type.title()}.read(data)\n "
|
||||
elif "vector" in arg_type.lower():
|
||||
sub_type = arg_type.split("<")[1][:-1]
|
||||
|
||||
write_types += "\n "
|
||||
write_types += "b.write(Vector(self.{}{}))\n ".format(
|
||||
arg_name, ", {}".format(sub_type.title()) if sub_type in core_types else ""
|
||||
write_types += "data.write(Vector(self.{}{}))\n ".format(
|
||||
arg_name, f", {sub_type.title()}" if sub_type in CORE_TYPES else ""
|
||||
)
|
||||
|
||||
read_types += "\n "
|
||||
read_types += "{} = TLObject.read(b{})\n ".format(
|
||||
arg_name, ", {}".format(sub_type.title()) if sub_type in core_types else ""
|
||||
read_types += "{} = TLObject.read(data{})\n ".format(
|
||||
arg_name, f", {sub_type.title()}" if sub_type in CORE_TYPES else ""
|
||||
)
|
||||
else:
|
||||
write_types += "\n "
|
||||
write_types += "b.write(self.{}.write())\n ".format(arg_name)
|
||||
write_types += f"data.write(self.{arg_name}.write())\n "
|
||||
|
||||
read_types += "\n "
|
||||
read_types += "{} = TLObject.read(b)\n ".format(arg_name)
|
||||
read_types += f"{arg_name} = TLObject.read(data)\n "
|
||||
|
||||
if c.docs:
|
||||
description = c.docs.split("|")[0].split("§")[1]
|
||||
docstring_args = description + "\n\n " + docstring_args
|
||||
slots = ", ".join([f'"{i[0]}"' for i in sorted_args])
|
||||
return_arguments = ", ".join([f"{i[0]}={i[0]}" for i in sorted_args])
|
||||
|
||||
with open("{}/{}.py".format(path, snek(c.name)), "w", encoding="utf-8") as f:
|
||||
if c.docs:
|
||||
f.write(
|
||||
pyrogram_template.format(
|
||||
notice=notice,
|
||||
class_name=capit(c.name),
|
||||
docstring_args=docstring_args,
|
||||
object_id=c.id,
|
||||
arguments=arguments,
|
||||
fields=fields
|
||||
)
|
||||
)
|
||||
else:
|
||||
f.write(
|
||||
mtproto_template.format(
|
||||
notice=notice,
|
||||
class_name=capit(c.name),
|
||||
docstring_args=docstring_args,
|
||||
object_id=c.id,
|
||||
arguments=arguments,
|
||||
fields=fields,
|
||||
read_types=read_types,
|
||||
write_types=write_types,
|
||||
return_arguments=", ".join(
|
||||
["{0}={0}".format(i[0]) for i in sorted_args if i != ("flags", "#")]
|
||||
),
|
||||
slots=", ".join(['"{}"'.format(i[0]) for i in sorted_args if i != ("flags", "#")]),
|
||||
qualname="{}.{}{}".format(c.section, "{}.".format(c.namespace) if c.namespace else "", c.name)
|
||||
)
|
||||
)
|
||||
compiled_combinator = combinator_tmpl.format(
|
||||
notice=notice,
|
||||
warning=WARNING,
|
||||
name=c.name,
|
||||
docstring=docstring,
|
||||
slots=slots,
|
||||
id=c.id,
|
||||
qualname=f"pyrogram.raw.{c.section}.{c.qualname}",
|
||||
arguments=arguments,
|
||||
fields=fields,
|
||||
read_types=read_types,
|
||||
write_types=write_types,
|
||||
return_arguments=return_arguments
|
||||
)
|
||||
|
||||
with open("{}/all.py".format(DESTINATION), "w", encoding="utf-8") as f:
|
||||
directory = "types" if c.section == "types" else c.section
|
||||
|
||||
dir_path = DESTINATION_PATH / directory / c.namespace
|
||||
|
||||
os.makedirs(dir_path, exist_ok=True)
|
||||
|
||||
module = c.name
|
||||
|
||||
if module == "Updates":
|
||||
module = "UpdatesT"
|
||||
|
||||
with open(dir_path / f"{snake(module)}.py", "w") as f:
|
||||
f.write(compiled_combinator)
|
||||
|
||||
d = namespaces_to_constructors if c.section == "types" else namespaces_to_functions
|
||||
|
||||
if c.namespace not in d:
|
||||
d[c.namespace] = []
|
||||
|
||||
d[c.namespace].append(c.name)
|
||||
|
||||
for namespace, types in namespaces_to_types.items():
|
||||
with open(DESTINATION_PATH / "base" / namespace / "__init__.py", "w") as f:
|
||||
f.write(f"{notice}\n\n")
|
||||
f.write(f"{WARNING}\n\n")
|
||||
|
||||
for t in types:
|
||||
module = t
|
||||
|
||||
if module == "Updates":
|
||||
module = "UpdatesT"
|
||||
|
||||
f.write(f"from .{snake(module)} import {t}\n")
|
||||
|
||||
if not namespace:
|
||||
f.write(f"from . import {', '.join(filter(bool, namespaces_to_types))}")
|
||||
|
||||
for namespace, types in namespaces_to_constructors.items():
|
||||
with open(DESTINATION_PATH / "types" / namespace / "__init__.py", "w") as f:
|
||||
f.write(f"{notice}\n\n")
|
||||
f.write(f"{WARNING}\n\n")
|
||||
|
||||
for t in types:
|
||||
module = t
|
||||
|
||||
if module == "Updates":
|
||||
module = "UpdatesT"
|
||||
|
||||
f.write(f"from .{snake(module)} import {t}\n")
|
||||
|
||||
if not namespace:
|
||||
f.write(f"from . import {', '.join(filter(bool, namespaces_to_constructors))}\n")
|
||||
|
||||
for namespace, types in namespaces_to_functions.items():
|
||||
with open(DESTINATION_PATH / "functions" / namespace / "__init__.py", "w") as f:
|
||||
f.write(f"{notice}\n\n")
|
||||
f.write(f"{WARNING}\n\n")
|
||||
|
||||
for t in types:
|
||||
module = t
|
||||
|
||||
if module == "Updates":
|
||||
module = "UpdatesT"
|
||||
|
||||
f.write(f"from .{snake(module)} import {t}\n")
|
||||
|
||||
if not namespace:
|
||||
f.write(f"from . import {', '.join(filter(bool, namespaces_to_functions))}")
|
||||
|
||||
with open(DESTINATION_PATH / "all.py", "w", encoding="utf-8") as f:
|
||||
f.write(notice + "\n\n")
|
||||
f.write("layer = {}\n\n".format(layer))
|
||||
f.write(WARNING + "\n\n")
|
||||
f.write(f"layer = {layer}\n\n")
|
||||
f.write("objects = {")
|
||||
|
||||
for c in combinators:
|
||||
path = ".".join(filter(None, [c.section, c.namespace, capit(c.name)]))
|
||||
f.write("\n {}: \"pyrogram.api.{}\",".format(c.id, path))
|
||||
f.write(f'\n {c.id}: "pyrogram.raw.{c.section}.{c.qualname}",')
|
||||
|
||||
f.write("\n 0xbc799737: \"pyrogram.api.core.BoolFalse\",")
|
||||
f.write("\n 0x997275b5: \"pyrogram.api.core.BoolTrue\",")
|
||||
f.write("\n 0x1cb5c415: \"pyrogram.api.core.Vector\",")
|
||||
f.write("\n 0x73f1f8dc: \"pyrogram.api.core.MsgContainer\",")
|
||||
f.write("\n 0xae500895: \"pyrogram.api.core.FutureSalts\",")
|
||||
f.write("\n 0x0949d9dc: \"pyrogram.api.core.FutureSalt\",")
|
||||
f.write("\n 0x3072cfa1: \"pyrogram.api.core.GzipPacked\",")
|
||||
f.write("\n 0x5bb8e511: \"pyrogram.api.core.Message\",")
|
||||
f.write('\n 0xbc799737: "pyrogram.raw.core.BoolFalse",')
|
||||
f.write('\n 0x997275b5: "pyrogram.raw.core.BoolTrue",')
|
||||
f.write('\n 0x1cb5c415: "pyrogram.raw.core.Vector",')
|
||||
f.write('\n 0x73f1f8dc: "pyrogram.raw.core.MsgContainer",')
|
||||
f.write('\n 0xae500895: "pyrogram.raw.core.FutureSalts",')
|
||||
f.write('\n 0x0949d9dc: "pyrogram.raw.core.FutureSalt",')
|
||||
f.write('\n 0x3072cfa1: "pyrogram.raw.core.GzipPacked",')
|
||||
f.write('\n 0x5bb8e511: "pyrogram.raw.core.Message",')
|
||||
|
||||
f.write("\n}\n")
|
||||
|
||||
for k, v in namespaces.items():
|
||||
with open("{}/{}/__init__.py".format(DESTINATION, k), "a", encoding="utf-8") as f:
|
||||
f.write("from . import {}\n".format(", ".join([i for i in v])) if v else "")
|
||||
|
||||
|
||||
if "__main__" == __name__:
|
||||
HOME = "."
|
||||
DESTINATION = "../../pyrogram/api"
|
||||
NOTICE_PATH = "../../NOTICE"
|
||||
start()
|
||||
HOME_PATH = Path(".")
|
||||
DESTINATION_PATH = Path("../../pyrogram/raw")
|
||||
NOTICE_PATH = Path("../../NOTICE")
|
||||
|
||||
start(format=False)
|
||||
|
Reference in New Issue
Block a user