Skip to content

Commit 66be54c

Browse files
committed
docs for 3.10.1 macos
0 parents  commit 66be54c

File tree

6 files changed

+1841
-0
lines changed

6 files changed

+1841
-0
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/target
2+
__pycache__
3+
.vscode
4+
.idea/
5+
6+
/.cargo/config
7+

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "rustpython-doc"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
once_cell = "1.10.0"

docs.inc.rs

Lines changed: 1575 additions & 0 deletions
Large diffs are not rendered by default.

generate_docs.py

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import re
2+
import sys
3+
import warnings
4+
from pydoc import ModuleScanner
5+
6+
7+
def scan_modules():
8+
"""taken from the source code of help('modules')
9+
10+
https://github.com/python/cpython/blob/63298930fb531ba2bb4f23bc3b915dbf1e17e9e1/Lib/pydoc.py#L2178"""
11+
modules = {}
12+
13+
def callback(path, modname, desc, modules=modules):
14+
if modname and modname[-9:] == ".__init__":
15+
modname = modname[:-9] + " (package)"
16+
if modname.find(".") < 0:
17+
modules[modname] = 1
18+
19+
def onerror(modname):
20+
callback(None, modname, None)
21+
22+
with warnings.catch_warnings():
23+
# ignore warnings from importing deprecated modules
24+
warnings.simplefilter("ignore")
25+
ModuleScanner().run(callback, onerror=onerror)
26+
return list(modules.keys())
27+
28+
29+
def import_module(module_name):
30+
import io
31+
from contextlib import redirect_stdout
32+
33+
# Importing modules causes ('Constant String', 2, None, 4) and
34+
# "Hello world!" to be printed to stdout.
35+
f = io.StringIO()
36+
with warnings.catch_warnings(), redirect_stdout(f):
37+
# ignore warnings caused by importing deprecated modules
38+
warnings.filterwarnings("ignore", category=DeprecationWarning)
39+
try:
40+
module = __import__(module_name)
41+
except Exception as e:
42+
return e
43+
return module
44+
45+
46+
def is_child(module, item):
47+
import inspect
48+
49+
item_mod = inspect.getmodule(item)
50+
return item_mod is module
51+
52+
53+
def traverse(module, names, item):
54+
import inspect
55+
56+
has_doc = inspect.ismodule(item) or inspect.isclass(item) or inspect.isbuiltin(item)
57+
if has_doc and isinstance(item.__doc__, str):
58+
yield names, item.__doc__
59+
attr_names = dir(item)
60+
for name in attr_names:
61+
if name in [
62+
"__class__",
63+
"__dict__",
64+
"__doc__",
65+
"__objclass__",
66+
"__name__",
67+
"__qualname__",
68+
"__annotations__",
69+
]:
70+
continue
71+
try:
72+
attr = getattr(item, name)
73+
except AttributeError:
74+
assert name == "__abstractmethods__", name
75+
continue
76+
77+
if module is item and not is_child(module, attr):
78+
continue
79+
80+
is_type_or_module = (type(attr) is type) or (type(attr) is type(__builtins__))
81+
new_names = names.copy()
82+
new_names.append(name)
83+
84+
if item == attr:
85+
pass
86+
elif not inspect.ismodule(item) and inspect.ismodule(attr):
87+
pass
88+
elif is_type_or_module:
89+
yield from traverse(module, new_names, attr)
90+
elif (
91+
callable(attr)
92+
or not issubclass(type(attr), type)
93+
or type(attr).__name__ in ("getset_descriptor", "member_descriptor")
94+
):
95+
if inspect.isbuiltin(attr):
96+
yield new_names, attr.__doc__
97+
else:
98+
assert False, (module, new_names, attr, type(attr).__name__)
99+
100+
101+
def traverse_all(root):
102+
from glob import glob
103+
import os.path
104+
105+
files = (
106+
glob(f"{root}/Lib/*")
107+
+ glob(f"{root}/vm/src/stdlib/*")
108+
+ glob(f"{root}/stdlib/src/*")
109+
)
110+
allowlist = set(
111+
[os.path.basename(file).lstrip("_").rsplit(".", 1)[0] for file in files]
112+
)
113+
for denied in ("this", "antigravity"):
114+
allowlist.remove(denied)
115+
116+
for module_name in scan_modules():
117+
if module_name.lstrip("_") not in allowlist:
118+
print("skipping:", module_name, file=sys.stderr)
119+
continue
120+
module = import_module(module_name)
121+
if hasattr(module, "__cached__"): # python module
122+
continue
123+
yield from traverse(module, [module_name], module)
124+
125+
builtin_types = [
126+
type(bytearray().__iter__()),
127+
type(bytes().__iter__()),
128+
type(dict().__iter__()),
129+
type(dict().values().__iter__()),
130+
type(dict().items().__iter__()),
131+
type(dict().values()),
132+
type(dict().items()),
133+
type(set().__iter__()),
134+
type(list().__iter__()),
135+
type(range(0).__iter__()),
136+
type(str().__iter__()),
137+
type(tuple().__iter__()),
138+
type(None),
139+
]
140+
for typ in builtin_types:
141+
names = ["builtins", typ.__name__]
142+
yield names, typ.__doc__
143+
yield from traverse(__builtins__, names, typ)
144+
145+
146+
def docs(rustpython_path):
147+
return ((".".join(names), escape(doc)) for names, doc in traverse_all(rustpython_path))
148+
149+
150+
UNICODE_ESCAPE = re.compile(r"\\u([0-9]+)")
151+
152+
153+
def escape(doc):
154+
if doc is None:
155+
return None
156+
return re.sub(UNICODE_ESCAPE, r"\\u{\1}", doc)
157+
158+
159+
def test_escape():
160+
input = r"It provides access to APT\u2019s idea of the"
161+
expected = r"It provides access to APT\u{2019}s idea of the"
162+
output = escape(input)
163+
assert output == expected
164+
165+
166+
if __name__ == "__main__":
167+
import sys
168+
import json
169+
170+
try:
171+
rustpython_path = sys.argv[1]
172+
except IndexError:
173+
print("1st argument is rustpython source code path")
174+
raise SystemExit
175+
176+
try:
177+
out_path = sys.argv[2]
178+
except IndexError:
179+
out_path = "-"
180+
181+
def dump(docs):
182+
yield "[\n"
183+
for name, doc in docs:
184+
if doc is None:
185+
yield f" ({json.dumps(name)}, None),\n"
186+
else:
187+
yield f" ({json.dumps(name)}, Some({json.dumps(doc)})),\n"
188+
yield "]\n"
189+
190+
out_file = open(out_path, "w") if out_path != "-" else sys.stdout
191+
out_file.writelines(dump(docs(rustpython_path)))

src/lib.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use once_cell::sync::Lazy;
2+
use std::collections::HashMap;
3+
4+
pub type Result<'a> = std::result::Result<Option<&'a str>, ()>;
5+
6+
pub struct Database<'a> {
7+
inner: HashMap<&'a str, Option<&'a str>>,
8+
}
9+
10+
impl<'a> Database<'a> {
11+
pub fn shared() -> &'static Self {
12+
static DATABASE: Lazy<Database> = Lazy::new(|| {
13+
let data = include!("../docs.inc.rs");
14+
let mut map = HashMap::with_capacity(data.len());
15+
for (item, doc) in data {
16+
map.insert(item, doc);
17+
}
18+
Database { inner: map }
19+
});
20+
&DATABASE
21+
}
22+
23+
pub fn try_path(&self, path: &str) -> Result {
24+
self.inner.get(path).copied().ok_or(())
25+
}
26+
27+
pub fn try_module_item(&self, module: &str, item: &str) -> Result {
28+
self.try_path(&format!("{}.{}", module, item))
29+
}
30+
}
31+
32+
#[cfg(test)]
33+
mod test {
34+
use super::*;
35+
36+
#[test]
37+
fn test_module_item() {
38+
let doc = Database::shared()
39+
.try_module_item("array", "_array_reconstructor")
40+
.unwrap();
41+
assert!(doc.is_some());
42+
}
43+
}

0 commit comments

Comments
 (0)