What misspellings / typos are supported in Python? - python

What misspellings / typos are supported in Python?
Not alternate spellings such as is_dir vs isdir, nor color vs colour but actual wrongly spelt aliases, such as proprety for property (which isn't supported).

As of Python 3.5 beta 3 the unittest.mock object now supports assret standing in for assert -- note that this is not the keyword assert, but any attribute of a mock object that matches the regular expression assert.* or assret.*.
Some explanation:
When a mock object is created the default for any attribute access is to return a new Mock, except in one case: if the attribute is one of assert_called_with, assert_called_once_with, assert_any_call, assert_has_calls, and assert_not_called, in which case some code is actually run.
The problem is if one forgets the exact name and uses, for example, assert_called, then instead of code running to check that the mock was called, a new mock is returned instead and the test one wrote passes instead of actually doing the test and possibly failing.
To combat this problem Mock now raises an AttributeError if any access is made to an attribute that starts with assert.
Besides assert, Mock will also raise an AttributeError if any access is made to an attribute that starts with assret.
If one does not want the extra protection (for assert and assret) one can use unsafe=True when creating the Mock.

Related

How to create a Mock which has functions' special (dunder) attributes

I have some code that uses functions as parameters and I've added some logging that includes __qualname__, this caused my unit tests to fail since the Mock object I passed in raises an AttributeError for __qualname__.
mock_func = Mock()
A simple solution to this problem is to manually add the expected attribute to the mock:
mock_func.__qualname__ = "mock_function"
Or add it to the spec of the mock when I create it:
mock_func = Moc(["__qualname__"])
But these solutions are unsatisfying since I would need to change them whenever I use a different built-in attribute (e.g. __name__).
Is there a simple way to create a Mock which behaves like a function?
The closest I found was this bug report that was opened on the wrong repository, and this request which has no replies.
You can simply use any function as spec for the mock.
mock_func = Mock(spec=max)
mock_func.__qualname__
>>> <Mock name='mock.__qualname__' id='140172665218496'>

Python __doc__ documentation on instances

I'd like to provide documentation (within my program) on certain dynamically created objects, but still fall back to using their class documentation. Setting __doc__ seems a suitable way to do so. However, I can't find many details in the Python help in this regard, are there any technical problems with providing documentation on an instance? For example:
class MyClass:
"""
A description of the class goes here.
"""
a = MyClass()
a.__doc__ = "A description of the object"
print( MyClass.__doc__ )
print( a.__doc__ )
__doc__ is documented as a writable attribute for functions, but not for instances of user defined classes. pydoc.help(a), for example, will only consider the __doc__ defined on the type in Python versions < 3.9.
Other protocols (including future use-cases) may reasonably bypass the special attributes defined in the instance dict, too. See Special method lookup section of the datamodel documentation, specifically:
For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.
So, depending on the consumer of the attribute, what you intend to do may not be reliable. Avoid.
A safe and simple alternative is just to use a different attribute name of your own choosing for your own use-case, preferably not using the __dunder__ syntax convention which usually indicates a special name reserved for some specific use by the implementation and/or the stdlib.
There are some pretty obvious technical problems; the question is whether or not they matter for your use case.
Here are some major uses for docstrings that your idiom will not help with:
help(a): Type help(a) in an interactive terminal, and you get the docstring for MyClass, not the docstring for a.
Auto-generated documentation: Unless you write your own documentation generator, it's not going to understand that you've done anything special with your a value. Many doc generators do have some way to specify help for module and class constants, but I'm not aware of any that will recognize your idiom.
IDE help: Many IDEs will not only auto-complete an expression, but show the relevant docstring in a tooltip. They all do this statically, and without some special-case code designed around your idiom (which they're unlikely to have, given that it's an unusual idiom), they're almost certain to fetch the docstring for the class, not the object.
Here are some where it might help:
Source readability: As a human reading your source, I can tell the intent from the a.__doc__ = … right near the construction of a. Then again, I could tell the same intent just as easily from a Sphinx comment on the constant.
Debugging: pdb doesn't really do much with docstrings, but some GUI debuggers wrapped around it do, and most of them are probably going to show a.__doc__.
Custom dynamic use of docstrings: Obviously any code that you write that does something with a.__doc__ is going to get the instance docstring if you want it to, and therefore can do whatever it wants with it. However, keep in mind that if you want to define your own "protocol", you should use your own name, not one reserved for the implementation.
Notice that most of the same is true for using a descriptor for the docstring:
>>> class C:
... #property
... def __doc__(self):
... return('C doc')
>>> c = C()
If you type c.__doc__, you'll get 'C doc', but help(c) will treat it as an object with no docstring.
It's worth noting that making help work is one of the reasons some dynamic proxy libraries generate new classes on the fly—that is, a proxy to underlying type Spam has some new type like _SpamProxy, instead of the same GenericProxy type used for proxies to Hams and Eggseses. The former allows help(myspam) to show dynamically-generated information about Spam. But I don't know how important a reason it is; often you already need dynamic classes to, e.g., make special method lookup work, at which point adding dynamic docstrings comes for free.
I think it's preferred to keep it under the class via your doc string as it will also aid any developer that works on the code. However if you are doing something dynamic that requires this setup then I don't see any reason why not. Just understand that it adds a level of indirection that makes things less clear to others.
Remember to K.I.S.S. where applicable :)
I just stumbled over this and noticed that at least with python 3.9.5 the behavior seems to have changed.
E.g. using the above example, when I call:
help(a)
I get:
Help on MyClass in module __main__:
<__main__.MyClass object>
A description of the object
Also for reference, have a look at the pydoc implementation which shows:
def _getowndoc(obj):
"""Get the documentation string for an object if it is not
inherited from its class."""
try:
doc = object.__getattribute__(obj, '__doc__')
if doc is None:
return None
if obj is not type:
typedoc = type(obj).__doc__
if isinstance(typedoc, str) and typedoc == doc:
return None
return doc
except AttributeError:
return None

Two Objects Created from the Same Class, isinstance = False

I'm trying to create some unit tests for some code here at work.
The code takes in an object and based on information within that object imports a specific module then creates an instance of it.
The test I am trying to write creates the object and then I check that it is an instance of the class I expect it to import. The issue is the isinstance check is failing.
Here is what my test looks like.
import importlib
from path.to.imported_api import SomeApi
api = importlib.import_module("path.to.imported_api").create_instance() # create_instance() is a function that returns SomeApi().
assert isinstance(api, SomeApi) # This returns false, but I am not sure why.
The reason for the difference is, that whereas both objects refer to the same module, they get different identifiers as you load a new module and bypass sys.modules. See also the explanation here: https://bugs.python.org/issue40427
A hack might be to compare the name:
assert isinstance(api.__class__.__name__, SomeApi.__name__)
There are a few things that could cause that:
So first, it could be that the api is just returning something that looks like SomeApi(). Also it coud is be that SomeApi is overwriting isinstance behaviour.

Use isinstance with an undefined class

Assume that class MyClass is sometimes, but not always, defined. I have a function foo(a=None) in which argument a can be None, a string, or an object of MyClass.
My question is: If MyClass is not defined in my Python session, how can I check the type of argument a in a fashion similar to isinstance without getting a NameError?
Note on duck-typing: I am deliberately limiting the function.
I'm using Python 2.6.x and Updating is not an option. A forward-compatible solution (especially for 2.7.x) is highly appreciated.
I would suggest a different approach: polyfill the class so all code that wants to refer to it can simply do so:
try:
from foo import Bar # load the native class
except ImportError:
class Bar:
pass # implement necessary parts here
You can put this into your own module and then from mymodule import Bar everywhere it's needed. That allows all your code to use Bar regardless of whether it's defined natively or not.
Even if redefining the class isn't your preferred way to handle this, handling the ImportError is still the way to handle this situation, since you will have to import the class either way and that's where the error will occur. Instead of defining the class, you may instead want to set a class_exists = False flag or something.
If MyClass isn't defined then you have no way to reference its type.
Therefore you can have no way to verify that type(a) has the correct value.
I workarounded the problem by overriding a method in MyClass and doing nothing in it (pass). After that I no longer needed to check its type.
Different workarounds may exist for different cases. Catching the NameError could be another one.
t = 'asdfas'
print(isinstance(t, str))
try:
print(isinstance(t, MyClass))
except NameError:
print(False)
Seems to me, that such a construct may appear in future python. Like typed python, which is quite new. And in typed python we have a possibility to use future types, in apos.

Testing failure of an assignment with unittest

One of my attributes is a property where the setter calls a validation function that raises an exception if the new value is invalid:
pos.offset = 0
# #offset.setter calls validate(offset=0)
# PositionError: Offset may not be 0.
I'm trying to add a test to ensure that this fails. However, I can't figure out how to get assertRaises to work with an assignment.
The normal syntax of assertRaises requires a method, not an attribute/property:
self.assertRaises(PositionError, pos.offset, 0)
# TypeError: 'int' object is not callable
The other forms I've tried are invalid Python:
self.assertRaises(PositionError, pos.offset = 0)
# SyntaxError: Keyword can't be an expression
self.assertRaises(PositionError, lambda: pos.offset = 0)
# SyntaxError: lambda cannot contain assignment
How do I test failure of assignment to a property?
Note: Python 2.6, I know unittest has some new features in 2.7
When you want to use unittest to test that an exception occurs in a block of code rather than just a function call, you can use assertRaises as a context manager:
with self.assertRaises(PositionError):
pos.offset = 0
This use can be found in the unittest docs.
While this is not available in Python 2.6, and won't work for you as such (I just saw your note), I think it's worth including among the answers, as it's probably the clearer way to do this for python 2.7+.
Before Python 2.7, you want to use setattr(object, name, value) (doc). This allows you to set a value to an attribute.
self.assertRaises(PositionError, setattr, pos, "offset", 0)
# ... ok
This should always work, because if the attribute is a property and thus "secretly" calls a function, it must be within a class. I don't think a standard assignment can fail (although an expression on the right side can fail, i.e. x = 1/0).

Categories