Skip to content

Commit

Permalink
Make type annotation optional for self argument of bound methods (#…
Browse files Browse the repository at this point in the history
…1626)

Make type annotation optional for the first argument (usually named
`self`) of bound methods to conform to PEP 484. Fixes #1578.

This is done by adding the missing type annotation in the syntactic
stage if there is no annotation present.
  • Loading branch information
EmilyBourne committed Nov 22, 2023
1 parent a96967f commit d01083b
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
- #1571 : Add support for the function `tuple`.
- #1493 : Add preliminary support for importing classes.
- \[INTERNALS\] Add `class_type` attribute to `TypedAstNode`.
- #1578 : Allow classes to avoid type annotations for the self argument of a method.

### Fixed

Expand Down
12 changes: 6 additions & 6 deletions docs/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,23 @@ import numpy as np
from pyccel.decorators import inline

class MyClass:
def __init__(self : 'MyClass', param1 : 'int', param2 : 'int'):
def __init__(self, param1 : 'int', param2 : 'int'):
self.param1 = param1
self.param2 = np.ones(param2)
print("MyClass Object created!")

@inline
def get_param(self : 'MyClass'):
def get_param(self):
print(self.param1, self.param2)

class MyClass1:
def __init__(self : 'MyClass1'):
def __init__(self):
print("MyClass1 Object created!")

def Method1(self : 'MyClass1', param1 : 'MyClass'):
def Method1(self, param1 : MyClass):
self.param = param1

def Method2(self : 'MyClass1'):
def Method2(self):
return MyClass(2, 4)

if __name__ == '__main__':
Expand Down Expand Up @@ -192,4 +192,4 @@ MyClass Object created!
## Limitations
It's important to note that Pyccel does not support class inheritance, properties, magic methods or class variables. For our first implementation, the focus of Pyccel is primarily on core class functionality and memory management.
It's important to note that Pyccel does not support class inheritance, properties, magic methods or static class variables. For our first implementation, the focus of Pyccel is primarily on core class functionality and memory management.
13 changes: 13 additions & 0 deletions pyccel/parser/syntactic.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ def _visit_AnnAssign(self, stmt):
return Assign(annotated_lhs, rhs)

def _visit_arguments(self, stmt):
is_class_method = len(self._context) > 2 and isinstance(self._context[-3], ast.ClassDef)

if stmt.vararg or stmt.kwarg:
errors.report(VARARGS, symbol = stmt,
Expand All @@ -489,6 +490,18 @@ def _visit_arguments(self, stmt):
new_arg.set_current_ast(a)
arguments.append(new_arg)

headers = self.scope.find(self._context[-2].name, 'headers') \
if isinstance(self._context[-2], ast.FunctionDef) else None

if is_class_method and not headers:
expected_self_arg = arguments[0]
if expected_self_arg.annotation is None:
class_name = self._context[-3].name
annotation = self._treat_type_annotation(class_name, PyccelSymbol(class_name))
arguments[0] = FunctionDefArgument(AnnotatedPyccelSymbol(expected_self_arg.name, annotation),
annotation=annotation,
value = expected_self_arg.value)

if stmt.kwonlyargs:
for a,d in zip(stmt.kwonlyargs,stmt.kw_defaults):
annotation=self._treat_type_annotation(a, self._visit(a.annotation))
Expand Down
2 changes: 1 addition & 1 deletion tests/pyccel/scripts/classes/classes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# pylint: disable=missing-class-docstring, missing-function-docstring, missing-module-docstring

class Point(object):
def __init__(self : 'Point', x : float, y : float):
def __init__(self, x : float, y : float):
self.x = x
self.y = y

Expand Down
12 changes: 6 additions & 6 deletions tests/pyccel/scripts/classes/classes_3.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@
# coding: utf-8

class Point:
def __init__(self : 'Point', x : float, y : float):
def __init__(self, x : float, y : float):
self.x = x
self.X = y

def set_coordinates(self : 'Point', x : float, y : float):
def set_coordinates(self, x : float, y : float):
self.x = x
self.X = y

def get_coordinates(self : 'Point'):
def get_coordinates(self):
return self.x, self.X

class Point1:
def __init__(self : 'Point1', x : float):
def __init__(self, x : float):
self.x = x

class Point2:
def __init__(self : 'Point2', y : float):
def __init__(self, y : float):
self.y = y

def test_func(self : 'Point2'):
def test_func(self):
p = Point1(self.y)
print(p.x)

Expand Down

0 comments on commit d01083b

Please sign in to comment.