So I made a function, and wanted to add annotations to it, and the compiler keeps giving me an error:
def square_root(x:number, eps:number) -> float:
pass
And the compiler returns this:
File "/Users/albertcalzaretto/Google Drive/CSC148H1/e1/e1a.py", line 1
def square_root(x, eps) -> float:
^
SyntaxError: invalid syntax
I've never used function annotations, and I've read several sources about it, and I don't think what I'm doing is wrong.
Two things:
You must be using Python 2.x somehow. Function annotations are only supported in Python 3.x. If you try to use them in Python 2.x, you will get a SyntaxError:
>>> def f() -> int:
File "<stdin>", line 1
def f() -> int:
^
SyntaxError: invalid syntax
>>>
If number is undefined (which I believe it is), then you need to make it a string so that you don't get a NameError. Below is a demonstration:
>>> def square_root(x:number, eps:number) -> float:
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'number' is not defined
>>>
>>> def square_root(x:'number', eps:'number') -> float:
... pass
...
>>>
Related
So i made some random stuff:
def println(text: str) -> str:
print(text)
if not type(text) == str:
raise TypeError("Text not string type")
println("Hello, World!")
Now, when i put a string inside the println() function it works perfectly fine. But if i put an integer inside the println() function it raises a TypeError with the location where it's coming from like this:
Traceback (most recent call last):
File "c:\Users\???\Desktop\leahnn files\python projects (do not delete)\Main files\main.py", line 6, in <module>
println(1)
File "c:\Users\???\Desktop\leahnn files\python projects (do not delete)\Main files\main.py", line 4, in println
raise TypeError("Text not string type")
TypeError: Text not string type
It does raise the TypeError but it's saying where it's coming from. I was wondering if you can just remove the location it's coming from and just say:
TypeError: Text not string type
If i just do:
def println(text: str) -> str:
print(text)
if not type(text) == str:
print("TypeError: Text not string type")
It's gonna print out the integer that is inside the println() function and it's gonna print the TypeError after the integer inside the println() function is done executing. Is it possible?
You can handle exception with
try-except clause
and in except just print error message.
See https://docs.python.org/3/tutorial/errors.html#handling-exceptions
try:
println(1)
except TypeError as err:
print(err)
I have a 'smart' open function that opens a variety of files and returns an IO-ish object type:
def sopen(anything_at_all: str, mode: str) -> FileIO:
...
And I use it in a print statement like:
with sopen('footxt.gz', mode = 'w+') as fout:
print("hello, world!", file=fout)
Then, when analyzing this code with mypy 0.812, I get the following mystery error:
Argument "fout" to "print" has incompatible type "FileIO"; expected "Optional[SupportsWrite[str]]"
Ok great: SupportsWrite is definitely better than FileIO, only one problem: when I adapt my code to support write using _typeshed.SupportsWrite, nothing gets better...
def sopen(anything_at_all: str, mode: str) \
-> Union[SupportsWrite[str],SupportsRead[str]]:
...
mypy wants exactly Optional[SupportsWrite]:
Argument "fout" to "print" has incompatible type "Union[SupportsWrite[str], SupportsRead[str]]"; expected "Optional[SupportsWrite[str]]"
Next I try casting, and creating some sort of type-casting enforcement, but in the middle of trying out my caster in the interpreter to see what errors fall out when:
>>> from _typeshed import SupportsRead, SupportsWrite
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named '_typeshed'
And now the fundamental problem is: how does one comply, in this situation, with mypy's wishes?
TL;DR Use typing.IO instead of FileIO. typing.IO supports all the return types that the built-in open might return.
print itself annotates its file argument as Optional[SupportsWrite[str]], so mypy is correct.
To fix the missing _typeshed module error (also correct, it is only available when type checking, not when the interpreter is executing code) you can use the if TYPE_CHECKING1 trick and then use string annotations.
The below almost satisfies mypy:
from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING:
from _typeshed import SupportsWrite
def sopen(anything_at_all: str, mode: str) -> 'Optional[SupportsWrite[str]]':
...
with sopen('footxt.gz', mode = 'w+') as fout:
print("hello, world!", file=fout)
Feeding this to mypy results with
test.py:9: error: Item "SupportsWrite[str]" of "Optional[SupportsWrite[str]]" has no attribute "__enter__"
test.py:9: error: Item "None" of "Optional[SupportsWrite[str]]" has no attribute "__enter__"
test.py:9: error: Item "SupportsWrite[str]" of "Optional[SupportsWrite[str]]" has no attribute "__exit__"
test.py:9: error: Item "None" of "Optional[SupportsWrite[str]]" has no attribute "__exit__"
Enters typing.IO.
Instead of messing with SupportsWrite directly, you can simply use typing.IO (which also happens to match open's return types). The following fully satisfies mypy:
from typing import IO
def sopen(anything_at_all: str, mode: str) -> IO:
...
with sopen('footxt.gz', mode = 'w+') as fout:
print("hello, world!", file=fout)
1 TYPE_CHECKING is a constant which is False by default, and is only being set to True by mypy and/or other type analyzing tools.
I'm trying to find an example of something in Python that can't be cast to a string.
>>> str(None)
'None'
>>> str(False)
'False'
>>> str(5)
'5'
>>> str(object)
"<class 'object'>"
>>> class Test:
... pass
...
>>> str(Test)
"<class '__main__.Test'>"
>>> str(Test())
'<__main__.Test object at 0x7f7e88a13630>'
Is there anything the entire Python universe that cannot be cast to str?
From the __str__ documentation:
The default implementation defined by the built-in type object
calls object.__repr__().
and object.__repr__ prints object name and address (at least in cpython). That's where your output '<__main__.Test object at 0x7f7e88a13630>' comes from. A class would have to override __str__ and raise an exception (or have a bug) to fail. There is little reason to do this and you'd be hard-pressed to find one that wasn't built to purpose.
Is everything in Python castable to a string?
Nope!
>>> class MyObject():
... def __str__(self):
... raise NotImplementedError("You can't string me!")
...
>>> str(MyObject())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __str__
NotImplementedError: You can't string me!
I would like to implement a deferred exception in Python that is OK to store somewhere but as soon as it is used in any way, it raises the exception that was deferred. Something like this:
# this doesn't work but it's a start
class DeferredException(object):
def __init__(self, exc):
self.exc = exc
def __getattr__(self, key):
raise self.exc
# example:
mydict = {'foo': 3}
try:
myval = obtain_some_number()
except Exception as e:
myval = DeferredException(e)
mydict['myval'] = myval
def plus_two(x):
print x+2
# later on...
plus_two(mydict['foo']) # prints 5
we_dont_use_this_val = mydict['myval'] # Always ok to store this value if not used
plus_two(mydict['myval']) # If obtain_some_number() failed earlier,
# re-raises the exception, otherwise prints the value + 2.
The use case is that I want to write code to analyze some values from incoming data; if this code fails but the results are never used, I want it to fail quietly; if it fails but the results are used later, then I'd like the failure to propagate.
Any suggestions on how to do this? If I use my DeferredException class I get this result:
>>> ke = KeyError('something')
>>> de = DeferredException(ke)
>>> de.bang # yay, this works
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __getattr__
KeyError: 'something'
>>> de+2 # boo, this doesn't
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'DeferredException' and 'int'
Read section 3.4.12 of the docs, "Special method lookup for new-style classes." It explains exactly the problem you have encountered. The normal attribute lookup is bypassed by the interpreter for certain operators, such as addition (as you found out the hard way). Thus the statement de+2 in your code never calls your getattr function.
The only solution, according to that section, is to insure that "the special method must be set on the class object itself in order to be consistently invoked by the interpreter."
Perhaps you'd be better off storing all your deferred exceptions in a global list, wrapping your entire program in a try:finally: statement, and printing out the whole list in the finally block.
For instance, if I have a call to the split method (i.e. some_string.split(":") )
Is is possible to mock this. I wanted to assert that the split function is called using assert_called_once_with
I confirm you can't do that because split() is a built-in attribute of str object and you can't set attributes of built-in or extension because they are readonly.
Below some inconclusive tests after trying into a Python 2.7.10 interpreter
>>> __builtins__.str.split
<method 'split' of 'str' objects>
>>> type(__builtins__.str.split)
<type 'method_descriptor'>
Trying to override it using a function
>>> type(lambda f:f)
<type 'function'>
>>> __builtins__.str.split = lambda f: f
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
Trying to override it using a callable (function or method)
>>> type(callable)
<type 'builtin_function_or_method'>
>>> __builtins__.str.split = callable
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
After having a look more deeply into the CPython source code here [1]. It's a limitation in Objects/typeobject.c introduce by the function list below. This function check if we try to set a readonly attribute and raise TypeError.
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
PyErr_Format(
PyExc_TypeError,
"can't set attributes of built-in/extension type '%s'",
type->tp_name);
return -1;
}
if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
return -1;
return update_slot(type, name);
}
[1] https://hg.python.org/cpython/file/tip/Objects/typeobject.c#l3022
Yes it is with a couple of caviats.
In my case I have successfully mocked str in python3 so I can assert that split is being called with a specific input
There are two caviats
With patch, I replaced the original str class with a new class that inherits from str
In the code that I was testing, I had to do a redundant string casting like str(str_val).split
Here's how one can do it:
class MyStr(str):
def split(self, sep=None, maxsplit=-1)):
expected_str = "some_input_mutated_inside_fn_before_split_called"
self.assertEqual(self, expected_str)
return super().split(sep=sep, maxsplit=maxsplit)
with patch('mymodule.str', new=MyStr):
output = mymodule.function_that_calls_string_split(
"some_input"
)