How to get the docstring of a function into a variable? - python

None of these commands will retrieve the docstring of a function and assign it to a variable. How can it be achieved?
I attempted various things. One of which is the help function, but it seems to activate an entire program as opposed to returning a string. I have tried various commands but none of them work to retrieve the docstring.
import PIL
PILCommands=dir('PIL')
ListA=[]
ListB=[]
ListC=[]
ListD=[]
ListE=[]
LisfF=[]
ListG=[]
ListH=[]
for x in PILCommands:
print(x)
try:
ListA.append(x.__doc__)
except:
pass
try:
ListB.append(x.__doc__())
except:
pass
try:
ListC.append(str(x))
except:
pass
try:
ListD.append(help(x))
except:
pass
try:
ListE.append(eval("x.__doc__"))
except:
pass
try:
ListF.append(eval("inspect.getdoc(x)"))
except:
pass
try:
ListG.append(eval("dir(x)"))
except:
pass
try:
ListH.append(eval("PIL.x.__doc__"))
except:
pass
print
print("Command1: x.__doc__")
print(ListA)
print
print("Command1: x.__doc__()")
print(ListB)
print
print("Command1: str(x)")
print(ListC)
print
print("help(x)")
print(ListD)
print
print('Command1: eval("eval("x.__doc__")')
print(ListE)
print
print('Command1: eval("inspect.getdoc(x)")')
print(ListE)
print
print('Command1: eval("dir(x)")')
print(ListG)
print
print('Command1: eval("PIL.x.__doc__")')
print(ListG)
Answer :
python << EOF
import inspect
import PIL
doc = inspect.getdoc(PIL)
print doc
print type(doc)
EOF
So it has no documentation .

You can use inspect.getdoc, that will process the docstring of the object and return it as string:
>>> import inspect
>>> doc = inspect.getdoc(I)
>>> print(doc)
This is the documentation string (docstring) of this function .
It contains an explanation and instruction for use .
Generally the documentation is stored in the __doc__ attribute:
>>> doc = I.__doc__
>>> print(doc)
This is the documentation string (docstring) of this function .
It contains an explanation and instruction for use .
But the __doc__ won't be cleaned: it might contain leading and trailing empty newlines and the indentation may not be consistent. So inspect.getdoc should be the preferred option.
The following is based on your original question:
To get the documentation of PIL functions you could use:
>>> import PIL
>>> import inspect
>>> doc = inspect.getdoc(PIL.Image.fromarray)
>>> print(doc)
Creates an image memory from an object exporting the array interface
(using the buffer protocol).
If obj is not contiguous, then the tobytes method is called
and :py:func:`~PIL.Image.frombuffer` is used.
:param obj: Object with array interface
:param mode: Mode to use (will be determined from type if None)
See: :ref:`concept-modes`.
:returns: An image object.
.. versionadded:: 1.1.6
To get the documentations of all functions in a module you need to use getattr:
for name in dir(PIL.Image):
docstring = inspect.getdoc(getattr(PIL.Image, name)) # like this
To get a list of all docstrings:
list_of_docs = [inspect.getdoc(getattr(PIL, obj)) for obj in dir(PIL)]
Or if you need to corresponding name then a dict would be better:
list_of_docs = {obj: inspect.getdoc(getattr(PIL, obj)) for obj in dir(PIL)}
However not everything actually has a documentation. For example the PIL.Image module has no docstring:
>>> PIL.Image.__doc__
None
>>> inspect.getdoc(PIL.Image)
None
and when attempting to get the docstring of an instance you might get surprising results:
>>> inspect.getdoc(PIL.__version__)
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.
That's because PIL.__version__ is a string instance and simply shows the docstring of its class: str:
>>> inspect.getdoc(str) # the built-in "str"
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.

Related

What type hint should I write when the return type is uncertain?

For example, if I define this function:
def open_pkl(src: str) -> ?:
with open('serialized.pkl', 'rb') as f:
data = pickle.load(f)
return data
what type hint should I write for the return value?
Now, I write the function as:
def open_pkl(src: str):
with open('serialized.pkl', 'rb') as f:
data = pickle.load(f)
return data
Is there type a hint for an uncertain return type?
You can use typing.Any to indicate an unconstrained type.
from typing import Any
def open_pkl(src: str) -> Any:
with open('serialized.pkl', 'rb') as f:
data = pickle.load(f)
return data
Do note that using Any as a type hint essentially turns off type checking. Per the docs:
Every type is compatible with Any.
Any is compatible with every type.
Hence, any usages of Any will pass type checking.
There are two options: object and typing.Any. Returning an object signals to the caller of the function that nothing can be assumed about the returned object (since everything is an object, saying that something is an object gives no information). So, if a user did
def open_pkl(src: str) -> object:
...
something = open_pkl('some/file')
print(len(something))
that would be a type violation, even if the object were a list, because objects per se don't have a __len__ method.
typing.Any, on the other hand, is like a wild card which could hypothetically be anything. So, if you reworked the above example to have a typing.Any return type, there would be no type violation. Does a typing.Any have a __len__ method? Maybe. Who says it couldn't?
To summarize, you should use object if you want to "force" (because type hints are just suggestions) your users to verify the type of any object returned by this function. Use typing.Any to be more lax.

ValueError: No object matches name: in Maya Python

I have a code that returns an error of
ValueError: No object matches name: s
I'm not sure why it is looking for the object s.
The code is as follows
import maya.cmds as cmds
def createOffsetGrp(objSel):
for obj in objSel:
p = cmds.listRelatives(obj,parent=True)
print (p)
createOffsetGrp('spine02_jnt')
By expectation, the print command should spit out Spine01_jnt which is the parent of the Spine02_jnt
Is there something I missed?
Thanks to duck typing in Python, sometimes such errors can be hard to catch. What is happening here is your function is expecting an array as argument, but you are passing a string.
Python supports iterating over a string as well, by listing out individual characters, which is why it is looking for the s in spine02_jnt. Passing your string within an array should solve your problem:
createOffsetGrp(['spine02_jnt'])
in addition of what crazyGamer, you can provide some support on string like this :
import maya.cmds as cmds
def createOffsetGrp(objSel):
# isinstance is used to check the type of the variable :
# i.e: isinstance(objSel, int)
# basestring is a type combining unicode and string types
if isinstance(objSel, basestring):
objSel = [objSel]
for obj in objSel:
p = cmds.listRelatives(obj,parent=True)
print (p)
createOffsetGrp('spine02_jnt')

Wrapping urllib3.HTTPResponse in io.TextIOWrapper

I use AWS boto3 library which returns me an instance of urllib3.response.HTTPResponse. That response is a subclass of io.IOBase and hence behaves as a binary file. Its read() method returns bytes instances.
Now, I need to decode csv data from a file received in such a way. I want my code to work on both py2 and py3 with minimal code overhead, so I use backports.csv which relies on io.IOBase objects as input rather than on py2's file() objects.
The first problem is that HTTPResponse yields bytes data for CSV file, and I have csv.reader which expects str data.
>>> import io
>>> from backports import csv # actually try..catch statement here
>>> from mymodule import get_file
>>> f = get_file() # returns instance of urllib3.HTTPResponse
>>> r = csv.reader(f)
>>> list(r)
Error: iterator should return strings, not bytes (did you open the file in text mode?)
I tried to wrap HTTPResponse with io.TextIOWrapper and got error 'HTTPResponse' object has no attribute 'read1'. This is expected becuase TextIOWrapper is intended to be used with BufferedIOBase objects, not IOBase objects. And it only happens on python2's implementation of TextIOWrapper because it always expects underlying object to have read1 (source), while python3's implementation checks for read1 existence and falls back to read gracefully (source).
>>> f = get_file()
>>> tw = io.TextIOWrapper(f)
>>> list(csv.reader(tw))
AttributeError: 'HTTPResponse' object has no attribute 'read1'
Then I tried to wrap HTTPResponse with io.BufferedReader and then with io.TextIOWrapper. And I got the following error:
>>> f = get_file()
>>> br = io.BufferedReader(f)
>>> tw = io.TextIOWrapper(br)
>>> list(csv.reader(f))
ValueError: I/O operation on closed file.
After some investigation it turns out that the error only happens when the file doesn't end with \n. If it does end with \n then the problem does not happen and everything works fine.
There is some additional logic for closing underlying object in HTTPResponse (source) which is seemingly causing the problem.
The question is: how can I write my code to
work on both python2 and python3, preferably with no try..catch or version-dependent branching;
properly handle CSV files represented as HTTPResponse regardless of whether they end with \n or not?
One possible solution would be to make a custom wrapper around TextIOWrapper which would make read() return b'' when the object is closed instead of raising ValueError. But is there any better solution, without such hacks?
Looks like this is an interface mismatch between urllib3.HTTPResponse and file objects. It is described in this urllib3 issue #1305.
For now there is no fix, hence I used the following wrapper code which seemingly works fine:
class ResponseWrapper(io.IOBase):
"""
This is the wrapper around urllib3.HTTPResponse
to work-around an issue shazow/urllib3#1305.
Here we decouple HTTPResponse's "closed" status from ours.
"""
# FIXME drop this wrapper after shazow/urllib3#1305 is fixed
def __init__(self, resp):
self._resp = resp
def close(self):
self._resp.close()
super(ResponseWrapper, self).close()
def readable(self):
return True
def read(self, amt=None):
if self._resp.closed:
return b''
return self._resp.read(amt)
def readinto(self, b):
val = self.read(len(b))
if not val:
return 0
b[:len(val)] = val
return len(val)
And use it as follows:
>>> f = get_file()
>>> r = csv.reader(ResponseWrapper(io.TextIOWrapper(io.BufferedReader(f))))
>>> list(r)
The similar fix was proposed by urllib3 maintainers in the bug report comments but it would be a breaking change hence for now things will probably not change, so I have to use wrapper (or do some monkey patching which is probably worse).

python string format calling a function

Is there a way to format with the new format syntax a string from a function call? for example:
"my request url was {0.get_full_path()}".format(request)
so it calls the function get_full_path function inside the string and not as a parameter in the format function.
EDIT:
Here is another example that will probably show my frustration better, this is what I would like:
"{0.full_name()} {0.full_last_name()} and my nick name is {0.full_nick_name()}".format(user)
this is what I want to avoid:
"{0} and {1} and my nick name is {2}".format(user.full_name(), user.full_last_name(), user.full_nick_name())
Not sure if you can modify the object, but you could modify or wrap the object to make the functions properties. Then they would look like attributes, and you could do it as
class WrapperClass(originalRequest):
#property
def full_name(self):
return super(WrapperClass, self).full_name()
"{0.full_name} {0.full_last_name} and my nick name is {0.full_nick_name}".format(user)
which IS legal.
Python 3.6 adds literal string interpolation, which is written with an f prefix. See PEP 0498 -- Literal String Interpolation.
This allows one to write
>>> x = 'hello'
>>> s = f'{x}'
>>> print(s)
hello
It should be noted that these are not actual strings, but represent code that evaluates to a string each time. In the above example, s will be of type str, with value 'hello'. You can't pass an f-string around, since it will be evaluated to the result str before being used (unlike str.format, but like every other string literal modifier, such as r'hello', b'hello', '''hello'''). (PEP 501 -- General purpose string interpolation (currently deferred) suggests a string literal that will evaluate to an object which can take substitutions later.)
Python does not directly support variable interpolation. This means that it lacks certain functionality (namely, function calling in strings) which other languages support.
So, there isn't really anything to say here other than no, you can't do that. That's just not how Python's formatting syntax works.
The best you have is this:
"my request url was {0}".format(request.get_full_path())
What about this very weird thing?
"my request url was %s and my post was %s"\
% (lambda r: (r.get_full_path(), r.POST))(request)
Explanation:
Classic way of formatting
Lambda function which takes a request and returns a tuple with what you want
Call the lambda inline as arguments for your string.
I still prefer the way you're doing it.
If you want readability you can do this:
path, post = request.get_full_path(), request.POST
"my request url was {} and my post was {}".format(path, post)
So summary of methods would be
(base) [1]~ $ cat r.py
# user is dict:
user = {'full_name': 'dict joe'}
print('{0[full_name]}'.format(user))
# user is obj:
class user:
#property
def full_name(self):
return 'attr joe'
print('{0.full_name}'.format(user()))
# Wrapper for arbitray values - as dict or by attr
class Getter:
def __init__(self, src):
self.src = src
def __getitem__(self, k):
return getattr(self.src, k, 'not found: %s' % k)
__getattr__ = __getitem__
print('{0[foo]} - {0.full_name}'.format(Getter(user())))
(base) [1]~ $ python r.py
dict joe
attr joe
not found: foo - attr joe

How to check if type of a variable is string? [duplicate]

This question already has answers here:
What's the canonical way to check for type in Python?
(15 answers)
Closed 6 months ago.
Is there a way to check if the type of a variable in python is a string, like:
isinstance(x,int);
for integer values?
In Python 3.x, the correct way to check if s is a string is
isinstance(s, str)
The bytes class isn't considered a string type in Python 3.
In Python 2.x, the correct check was
isinstance(s, basestring)
basestring is the abstract superclass of str and unicode. It can be used to test whether an object is an instance of either str or unicode.
I know this is an old topic, but being the first one shown on google and given that I don't find any of the answers satisfactory, I'll leave this here for future reference:
six is a Python 2 and 3 compatibility library which already covers this issue. You can then do something like this:
import six
if isinstance(value, six.string_types):
pass # It's a string !!
Inspecting the code, this is what you find:
import sys
PY3 = sys.version_info[0] == 3
if PY3:
string_types = str,
else:
string_types = basestring,
In Python 3.x or Python 2.7.6
if type(x) == str:
you can do:
var = 1
if type(var) == int:
print('your variable is an integer')
or:
var2 = 'this is variable #2'
if type(var2) == str:
print('your variable is a string')
else:
print('your variable IS NOT a string')
hope this helps!
Use type() or isinstance()
I don't know why not a single answer before me contains this simple type(my_variable) is str syntax, but using type() like this seems the most-logical and simple to me, by far:
(tested in Python3):
# Option 1: check to see if `my_variable` is of type `str`
type(my_variable) is str
# Option 2: check to see if `my_variable` is of type `str`, including
# being a subclass of type `str` (ie: also see if `my_variable` is any object
# which inherits from `str` as a parent class)
isinstance(my_variable, str)
The Python type() built-in function documentation is here: https://docs.python.org/3/library/functions.html#type. It states, in part, the following. Notice the note about isinstance():
class type(object)
class type(name, bases, dict, **kwds)
With one argument, return the type of an object. The return value is a type object and generally the same object as returned by object.__class__.
The isinstance() built-in function is recommended for testing the type of an object, because it takes subclasses into account.
So, if you're checking the type of a class object instead of a simple variable, and you need to take subclasses into account, then use isinstance() instead. See its documentation here: https://docs.python.org/3/library/functions.html#isinstance.
Example code:
my_str = "hello"
my_int = 7
print(type(my_str) is str)
print(type(my_int) is str)
print()
print(isinstance(my_str, str))
print(isinstance(my_int, str))
Output:
True
False
True
False
The type module also exists if you are checking more than ints and strings.
http://docs.python.org/library/types.html
Edit based on better answer below. Go down about 3 answers and find out about the coolness of basestring.
Old answer:
Watch out for unicode strings, which you can get from several places, including all COM calls in Windows.
if isinstance(target, str) or isinstance(target, unicode):
since basestring isn't defined in Python3, this little trick might help to make the code compatible:
try: # check whether python knows about 'basestring'
basestring
except NameError: # no, it doesn't (it's Python3); use 'str' instead
basestring=str
after that you can run the following test on both Python2 and Python3
isinstance(myvar, basestring)
Python 2 / 3 including unicode
from __future__ import unicode_literals
from builtins import str # pip install future
isinstance('asdf', str) # True
isinstance(u'asdf', str) # True
http://python-future.org/overview.html
Lots of good suggestions provided by others here, but I don't see a good cross-platform summary. The following should be a good drop in for any Python program:
def isstring(s):
# if we use Python 3
if (sys.version_info[0] >= 3):
return isinstance(s, str)
# we use Python 2
return isinstance(s, basestring)
In this function, we use isinstance(object, classinfo) to see if our input is a str in Python 3 or a basestring in Python 2.
So,
You have plenty of options to check whether your variable is string or not:
a = "my string"
type(a) == str # first
a.__class__ == str # second
isinstance(a, str) # third
str(a) == a # forth
type(a) == type('') # fifth
This order is for purpose.
Also I want notice that if you want to check whether the type of a variable is a specific kind, you can compare the type of the variable to the type of a known object.
For string you can use this
type(s) == type('')
Alternative way for Python 2, without using basestring:
isinstance(s, (str, unicode))
But still won't work in Python 3 since unicode isn't defined (in Python 3).
Here is my answer to support both Python 2 and Python 3 along with these requirements:
Written in Py3 code with minimal Py2 compat code.
Remove Py2 compat code later without disruption. I.e. aim for deletion only, no modification to Py3 code.
Avoid using six or similar compat module as they tend to hide away what
is trying to be achieved.
Future-proof for a potential Py4.
import sys
PY2 = sys.version_info.major == 2
# Check if string (lenient for byte-strings on Py2):
isinstance('abc', basestring if PY2 else str)
# Check if strictly a string (unicode-string):
isinstance('abc', unicode if PY2 else str)
# Check if either string (unicode-string) or byte-string:
isinstance('abc', basestring if PY2 else (str, bytes))
# Check for byte-string (Py3 and Py2.7):
isinstance('abc', bytes)
a = '1000' # also tested for 'abc100', 'a100bc', '100abc'
isinstance(a, str) or isinstance(a, unicode)
returns True
type(a) in [str, unicode]
returns True
If you do not want to depend on external libs, this works both for Python 2.7+ and Python 3 (http://ideone.com/uB4Kdc):
# your code goes here
s = ["test"];
#s = "test";
isString = False;
if(isinstance(s, str)):
isString = True;
try:
if(isinstance(s, basestring)):
isString = True;
except NameError:
pass;
if(isString):
print("String");
else:
print("Not String");
You can simply use the isinstance function to make sure that the input data is of format string or unicode. Below examples will help you to understand easily.
>>> isinstance('my string', str)
True
>>> isinstance(12, str)
False
>>> isinstance('my string', unicode)
False
>>> isinstance(u'my string', unicode)
True
Summarizing:
There doesn't seem to be a portable way to do it if you want both Python2 and Python3, and want to include unicode as well. I wound up using this idiom:
# Near the top of my program
if sys.version_info[0] >= 3:
basestring = str
Then any time I want to test an object to see if it's a string:
if isinstance(obj, basestring):
...
Frankly, I'm a little shocked that Python3 dropped basestring as well as types.StringTypes. I see no reason to drop them, and keeping either of them would have made this problem solveable.
s = '123'
issubclass(s.__class__, str)
This is how I do it:
if type(x) == type(str()):
I've seen:
hasattr(s, 'endswith')
>>> thing = 'foo'
>>> type(thing).__name__ == 'str' or type(thing).__name__ == 'unicode'
True

Categories