Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d9d4538

Browse files
authored
Merge pull request #3783 from ChJR/feature/fix_decorators
Fix decorators
2 parents 2e77581 + 8ef21ee commit d9d4538

File tree

6 files changed

+140
-38
lines changed

6 files changed

+140
-38
lines changed

Lib/test/test_decorators.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,12 @@ def func(x):
9494
self.assertEqual(repr(wrapper), format_str.format(func))
9595
return wrapper
9696

97-
# TODO: RUSTPYTHON
98-
@unittest.expectedFailure
9997
def test_staticmethod(self):
10098
wrapper = self.check_wrapper_attrs(staticmethod, '<staticmethod({!r})>')
10199

102100
# bpo-43682: Static methods are callable since Python 3.10
103101
self.assertEqual(wrapper(1), 1)
104102

105-
# TODO: RUSTPYTHON
106-
@unittest.expectedFailure
107103
def test_classmethod(self):
108104
wrapper = self.check_wrapper_attrs(classmethod, '<classmethod({!r})>')
109105

@@ -203,13 +199,12 @@ def unimp(func):
203199
code = compile(codestr, "test", "exec")
204200
self.assertRaises(exc, eval, code, context)
205201

206-
# TODO: RUSTPYTHON; := operator is invalid syntax
207-
# def test_expressions(self):
208-
# for expr in (
209-
# "(x,)", "(x, y)", "x := y", "(x := y)", "x @y", "(x @ y)", "x[0]",
210-
# "w[x].y.z", "w + x - (y + z)", "x(y)()(z)", "[w, x, y][z]", "x.y",
211-
# ):
212-
# compile(f"@{expr}\ndef f(): pass", "test", "exec")
202+
def test_expressions(self):
203+
for expr in (
204+
"(x,)", "(x, y)", "x := y", "(x := y)", "x @y", "(x @ y)", "x[0]",
205+
"w[x].y.z", "w + x - (y + z)", "x(y)()(z)", "[w, x, y][z]", "x.y",
206+
):
207+
compile(f"@{expr}\ndef f(): pass", "test", "exec")
213208

214209
def test_double(self):
215210
class C(object):
@@ -297,8 +292,6 @@ def bar(): return 42
297292
self.assertEqual(bar(), 42)
298293
self.assertEqual(actions, expected_actions)
299294

300-
# TODO: RUSTPYTHON
301-
@unittest.expectedFailure
302295
def test_wrapped_descriptor_inside_classmethod(self):
303296
class BoundWrapper:
304297
def __init__(self, wrapped):
@@ -337,8 +330,6 @@ def outer(cls):
337330
self.assertEqual(Class().inner(), 'spam')
338331
self.assertEqual(Class().outer(), 'eggs')
339332

340-
# TODO: RUSTPYTHON
341-
@unittest.expectedFailure
342333
def test_wrapped_classmethod_inside_classmethod(self):
343334
class MyClassMethod1:
344335
def __init__(self, func):

Lib/test/test_reprlib.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,6 @@ def inner():
198198
r'int object at 0x[0-9A-Fa-f]+>')
199199
self.assertRegex(r(x), r'<cell at 0x.*\.\.\..*>')
200200

201-
# TODO: RUSTPYTHON
202-
@unittest.expectedFailure
203201
def test_descriptors(self):
204202
eq = self.assertEqual
205203
# method descriptors

parser/src/python.lalrpop

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ ClassDef: ast::Stmt = {
634634

635635
// Decorators:
636636
Decorator: ast::Expr = {
637-
<location:@L>"@" <p:Test> "\n" => {
637+
<location:@L>"@" <p:NamedExpressionTest> "\n" => {
638638
p
639639
},
640640
};

parser/src/python.rs

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

vm/src/builtins/classmethod.rs

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{PyBoundMethod, PyType, PyTypeRef};
1+
use super::{PyBoundMethod, PyStr, PyType, PyTypeRef};
22
use crate::{
33
class::PyClassImpl,
44
common::lock::PyMutex,
@@ -53,22 +53,33 @@ impl GetDescriptor for PyClassMethod {
5353
cls: Option<PyObjectRef>,
5454
vm: &VirtualMachine,
5555
) -> PyResult {
56-
let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?;
57-
let cls = cls.unwrap_or_else(|| obj.class().clone().into());
58-
let callable = zelf.callable.lock().clone();
59-
Ok(PyBoundMethod::new_ref(cls, callable, &vm.ctx).into())
56+
let (zelf, _obj) = Self::_unwrap(zelf, obj, vm)?;
57+
let cls = cls.unwrap_or_else(|| _obj.class().clone().into());
58+
let call_descr_get: PyResult<PyObjectRef> = zelf.callable.lock().get_attr("__get__", vm);
59+
match call_descr_get {
60+
Err(_) => Ok(PyBoundMethod::new_ref(cls, zelf.callable.lock().clone(), &vm.ctx).into()),
61+
Ok(call_descr_get) => vm.invoke(&call_descr_get, (cls.clone(), cls)),
62+
}
6063
}
6164
}
6265

6366
impl Constructor for PyClassMethod {
6467
type Args = PyObjectRef;
6568

6669
fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult {
67-
PyClassMethod {
70+
let doc = callable.get_attr("__doc__", vm);
71+
72+
let result = PyClassMethod {
6873
callable: PyMutex::new(callable),
6974
}
70-
.into_ref_with_type(vm, cls)
71-
.map(Into::into)
75+
.into_ref_with_type(vm, cls)?;
76+
let obj = PyObjectRef::from(result);
77+
78+
if let Ok(doc) = doc {
79+
obj.set_attr("__doc__", doc, vm)?;
80+
}
81+
82+
Ok(obj)
7283
}
7384
}
7485

@@ -100,6 +111,51 @@ impl PyClassMethod {
100111
self.callable.lock().clone()
101112
}
102113

114+
#[pyproperty(magic)]
115+
fn wrapped(&self) -> PyObjectRef {
116+
self.callable.lock().clone()
117+
}
118+
119+
#[pyproperty(magic)]
120+
fn module(&self, vm: &VirtualMachine) -> PyResult {
121+
self.callable.lock().get_attr("__module__", vm)
122+
}
123+
124+
#[pyproperty(magic)]
125+
fn qualname(&self, vm: &VirtualMachine) -> PyResult {
126+
self.callable.lock().get_attr("__qualname__", vm)
127+
}
128+
129+
#[pyproperty(magic)]
130+
fn name(&self, vm: &VirtualMachine) -> PyResult {
131+
self.callable.lock().get_attr("__name__", vm)
132+
}
133+
134+
#[pyproperty(magic)]
135+
fn annotations(&self, vm: &VirtualMachine) -> PyResult {
136+
self.callable.lock().get_attr("__annotations__", vm)
137+
}
138+
139+
#[pymethod(magic)]
140+
fn repr(&self, vm: &VirtualMachine) -> Option<String> {
141+
let callable = self.callable.lock().repr(vm).unwrap();
142+
let class = Self::class(vm);
143+
144+
match (
145+
class
146+
.qualname(vm)
147+
.downcast_ref::<PyStr>()
148+
.map(|n| n.as_str()),
149+
class.module(vm).downcast_ref::<PyStr>().map(|m| m.as_str()),
150+
) {
151+
(None, _) => None,
152+
(Some(qualname), Some(module)) if module != "builtins" => {
153+
Some(format!("<{}.{}({})>", module, qualname, callable))
154+
}
155+
_ => Some(format!("<{}({})>", class.slot_name(), callable)),
156+
}
157+
}
158+
103159
#[pyproperty(magic)]
104160
fn isabstractmethod(&self, vm: &VirtualMachine) -> PyObjectRef {
105161
match vm.get_attribute_opt(self.callable.lock().clone(), "__isabstractmethod__") {

vm/src/builtins/staticmethod.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,16 @@ impl Constructor for PyStaticMethod {
4141
type Args = PyObjectRef;
4242

4343
fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult {
44-
PyStaticMethod { callable }
45-
.into_ref_with_type(vm, cls)
46-
.map(Into::into)
44+
let doc = callable.get_attr("__doc__", vm);
45+
46+
let result = PyStaticMethod { callable }.into_ref_with_type(vm, cls)?;
47+
let obj = PyObjectRef::from(result);
48+
49+
if let Ok(doc) = doc {
50+
obj.set_attr("__doc__", doc, vm)?;
51+
}
52+
53+
Ok(obj)
4754
}
4855
}
4956

@@ -68,6 +75,56 @@ impl PyStaticMethod {
6875

6976
#[pyimpl(with(Callable, GetDescriptor, Constructor), flags(BASETYPE, HAS_DICT))]
7077
impl PyStaticMethod {
78+
#[pyproperty(magic)]
79+
fn func(&self) -> PyObjectRef {
80+
self.callable.clone()
81+
}
82+
83+
#[pyproperty(magic)]
84+
fn wrapped(&self) -> PyObjectRef {
85+
self.callable.clone()
86+
}
87+
88+
#[pyproperty(magic)]
89+
fn module(&self, vm: &VirtualMachine) -> PyResult {
90+
self.callable.get_attr("__module__", vm)
91+
}
92+
93+
#[pyproperty(magic)]
94+
fn qualname(&self, vm: &VirtualMachine) -> PyResult {
95+
self.callable.get_attr("__qualname__", vm)
96+
}
97+
98+
#[pyproperty(magic)]
99+
fn name(&self, vm: &VirtualMachine) -> PyResult {
100+
self.callable.get_attr("__name__", vm)
101+
}
102+
103+
#[pyproperty(magic)]
104+
fn annotations(&self, vm: &VirtualMachine) -> PyResult {
105+
self.callable.get_attr("__annotations__", vm)
106+
}
107+
108+
#[pymethod(magic)]
109+
fn repr(&self, vm: &VirtualMachine) -> Option<String> {
110+
let callable = self.callable.repr(vm).unwrap();
111+
let class = Self::class(vm);
112+
113+
match (
114+
class
115+
.qualname(vm)
116+
.downcast_ref::<PyStr>()
117+
.map(|n| n.as_str()),
118+
class.module(vm).downcast_ref::<PyStr>().map(|m| m.as_str()),
119+
) {
120+
(None, _) => None,
121+
(Some(qualname), Some(module)) if module != "builtins" => {
122+
Some(format!("<{}.{}({})>", module, qualname, callable))
123+
}
124+
_ => Some(format!("<{}({})>", class.slot_name(), callable)),
125+
}
126+
}
127+
71128
#[pyproperty(magic)]
72129
fn isabstractmethod(&self, vm: &VirtualMachine) -> PyObjectRef {
73130
match vm.get_attribute_opt(self.callable.clone(), "__isabstractmethod__") {

0 commit comments

Comments
 (0)