I have been using importlib to get the module from an imported python file and would like to get the line number where each class is defined in the python file.
For example I have something like this:
testSpec = importlib.util.spec_from_file_location("", old_file)
testModule = importlib.util.module_from_spec(testSpec)
testSpec.loader.exec_module(testModule)
Where old_file is a python file (lets call it old.py). Then using the inspect library I can find all of the classes from old.py in this way:
for name, obj in inspect.getmembers(testModule):
if inspect.isclass(obj):
print(name)
This gives me all of the created class names from old.py which is correct. However, what I would like to do is also get the line number where this class appears in old.py. I have tried to add this line in the if statement right after the print statement: print(inspect.getsourcelines(obj))
However, this errors out in this way:
File "old.py", line 665, in getfile
raise TypeError('{!r} is a built-in class'.format(object))
TypeError: <class '.exampleClassName'> is a built-in class
I am not sure why it considers this user-created class a built-in class, but is there another way that I can just get the line number where this class is defined in old.py? For example if old.py looks like this:
#test comment line 1
#test comment line 2
class exampleClassName:
test = 0
Then when I have the class object exampleClassName I would expect to print out 4 from inspect.getsourcelines(obj) since it is defined on line 4.
An option would be to loop through the file with open and .readline(), and see where the line matches class, then save the line (count) number and class name into a dict.
Related
I'm trying to take a UK mobile phone number input from a web form and use Python to clean it into a E.164 format, then validate it, before entering it into a database.
The library I'm trying to use is "Phonenumbers" and the code I'm experimenting with so far is:
def Phone():
my_number = '+4407808765066'
clean_phone = phonenumbers.parse(my_number, "GB")
cleaner_phone = phonenumbers.format_number(clean_phone,
phonenumbers.PhoneNumberFormat.E164)
valid = phonenumbers.is_possible_number(cleaner_phone)
print(cleaner_phone)
Just working through the logic, my expectation is that it should take the contents of my_number variable, format it through into the clean_phone variable, then format it to E.164 standard before passing it to the validation and return the output to valid. The print statement is for me to see the output.
Everything looks to work ok if I comment out the valid variable line. As soon as I uncomment it, I get an error (see below).
Traceback (most recent call last):
File "phone_test.py", line 14, in <module>
Phone()
File "phone_test.py", line 10, in Phone
valid = phonenumbers.is_possible_number(cleaner_phone)
File "D:\Dropbox\Coding Projects\learner_driver_app\env\lib\site-packages\phonenumbers\phonenumberutil.py", line 2257, in is_possible_number
result = is_possible_number_with_reason(numobj)
File "D:\Dropbox\Coding Projects\learner_driver_app\env\lib\site-packages\phonenumbers\phonenumberutil.py", line 2358, in is_possible_number_with_reason
return is_possible_number_for_type_with_reason(numobj, PhoneNumberType.UNKNOWN)
File "D:\Dropbox\Coding Projects\learner_driver_app\env\lib\site-packages\phonenumbers\phonenumberutil.py", line 2393, in is_possible_number_for_type_with_reason
national_number = national_significant_number(numobj)
File "D:\Dropbox\Coding Projects\learner_driver_app\env\lib\site-packages\phonenumbers\phonenumberutil.py", line 1628, in national_significant_number
if numobj.italian_leading_zero:
AttributeError: 'str' object has no attribute 'italian_leading_zero'
Where am I going wrong?
Your my_number is a variable of type str (string), thus the last line of your error). The string class does not know the attribute national_number.
Reading through their examples on GitHub, I suspect you need to pass your string through the parse() function first before you can use functions from the library.
def Phone():
my_number = '+4407811111111'
number_prased = phonenumbers.parse(my_number, None) # this is new
clean_phone = phonenumbers.format_number(number_parsed,
phonenumbers.PhoneNumberFormat.E164)
return clean_phone
The None in parse() may be replaced by a country code if it is known. Otherwise, it will try to figure it out but may fail.
Edit to account for more information in the original question:
Apparently phonenumbers.format_number() returns a string, therefore you have to re-parse the number again to get an object of type phonenumbers.phonenumber.PhoneNumber (you can check the type of objects with type(my_object)). After that, your code will return True.
You can't use the format_number function with a string as argument, it expects a PhoneNumber object.
You can get one by using the parse function.
See https://github.com/daviddrysdale/python-phonenumbers/tree/dev/python#example-usage
I have the following JSON object located in its own file called build.json:
{
"name": "utils",
"version": "1.0.0",
"includes": [],
"libraries": [],
"testLibraries": []
}
I obtain this object in my Python program using the following method:
def getPackage(packageName):
jsonFilePath = os.path.join(SRCDIR, packageName, "build.json")
packageJson = None
try:
with open(jsonFilePath, "r") as jsonFile:
packageJson = json.load(jsonFile)
except:
return None
return packageJson
I verify that the JSON object for the current package (which is one of many packages I am iterating over) did not come back None in the following method. Note that I am temporarily printing out the keys of the dictionary:
def compileAllPackages():
global COMPILED_PACKAGES
for packageName in os.listdir(SRCDIR):
package = getPackage(packageName)
if package == None:
continue
# TEMP ==============
for i in package:
print(i)
# ===================
compiledSuccessfully = compilePackage(package)
if not compiledSuccessfully:
return False
return True
Lastly, I am currently also printing out the keys of the dictionary once it is received in the compilePackage function:
def compilePackage(package):
global COMPILED_PACKAGES, INCLUDE_TESTS
# TEMP ==============
for i in package:
print(i)
# ===================
...
Output from compileAllPackages function:
name
version
includes
libraries
testLibraries
Output from compilePackage function:
name
version
includes
libraries
testLibraries
u
t
i
l
s
I can not for the life of me figure out what is happening to my dictionary during that function call??? Please note that the build.json file is located within a directory named "utils".
Edit:
The Python script is located separate from the build.json file and works on absolute paths. It should also be noted that after getting that strange output, I also get the following exception when trying to access a valid key later (it seems to think the dictionary is a string?...):
Traceback (most recent call last):
File "/Users/nate/bin/BuildTool/unix/build.py", line 493, in <module>
main()
File "/Users/nate/bin/BuildTool/unix/build.py", line 481, in main
compiledSuccessfully = compileAllPackages()
File "/Users/nate/bin/BuildTool/unix/build.py", line 263, in compileAllPackages
compiledSuccessfully = compilePackage(package)
File "/Users/nate/bin/BuildTool/unix/build.py", line 287, in compilePackage
compiledSuccessfully = compilePackage(include)
File "/Users/nate/bin/BuildTool/unix/build.py", line 279, in compilePackage
includes = getPackageIncludes(package)
File "/Users/nate/bin/BuildTool/unix/build.py", line 194, in getPackageIncludes
includes = [package["name"]] # A package always includes itself
TypeError: string indices must be integers
Edit: If I change the parameter name to something other than 'package', I no longer get that weird output or an exception later on. This is not necessarily a fix, however, as I do not know what could be wrong with the name 'package'. There are no globals named as such either.
The answer ended up being very stupid. compilePackage() has the possibility of being called recursively, due to any dependencies the package may rely on. In recursive calls to the function, I was passing a string to the function rather than a dictionary.
I tried your code and the result is like this
Output from compileAllPackages function:
name
version
includes
libraries
testLibraries
Output from compilePackage function:
name
version
includes
libraries
testLibraries
My directory structure is like this
├── test.py
└── tt
└── cc
└── utils
└── build.json
I think your code is correct, it should be that the path parameter you passed is incorrect.
I have problem:
I am using this package: https://github.com/ulule/django-badgify
It works perfectly, but now I need to create Custom model Badge. I have made everything, as in docs:
main.models.py:
from badgify.models.base.badge import Badge as BaseBadge
class GuidaBadge(BaseBadge):
class Meta(BaseBadge.Meta):
abstract = False
settings.py:
BADGIFY_BADGE_MODEL = "main.models.GuidaBadge"
But it cause error:
File "D:\virtenvs\codeguida\codeguida\main\models.py", line 11, in <module>
from badgify.models.base.badge import Badge as BaseBadge
File "D:\virtenvs\codeguida\lib\site-packages\badgify\models\__init__.py", line 8, in <module>
Badge = load_class(settings.BADGE_MODEL)
File "D:\virtenvs\codeguida\lib\site-packages\badgify\utils.py", line 88, in load_class
raise exceptions.ImproperlyConfigured(txt)
django.core.exceptions.ImproperlyConfigured: Backend module "main.models" does not define a "GuidaBadge" class.
That is, https://github.com/ulule/django-badgify/blob/master/badgify/utils.py#L79
It seems that Python can`t find "GuidaBadge" class. So I have tried to use function load_class() in shell - it return right class...
I think that the error cause, in this way:
As we can see in Traceback, firstly:
File "D:\virtenvs\codeguida\codeguida\main\models.py", line 11, in <module>
from badgify.models.base.badge import Badge as BaseBadge
Program asks python to import Badge class from badgify package
Then Python tried to import it, and encounter with
File "D:\virtenvs\codeguida\lib\site-packages\badgify\models\__init__.py", line 8, in <module>
Badge = load_class(settings.BADGE_MODEL)
Here program asks python to load_class from string (that is stored in settings, e.g. 'main.models.GuidaBadge')
But Python has not run this part of models, yet. And it cause error that there is not class "GuidaBadge" in "main.models".
Am I right?
How to fix it?
dont do
from badgify.models.base.badge import Badge as BaseBadge
instead do
import badgify.models.base.badge
class GuidaBadge(badgify.models.base.badge.Badge):
class Meta(BaseBadge.Meta):
abstract = False
"from" and "as" imports are having problems with circularity because of namespace changes (the from imported module is not recognized as the original model because it is imported as a different namespace).
main.models.py:
Is your file named that way or is it models.py that lives in main directory? If first one, change it to second one.
Check also that you have __init__.py file in main directory and that your main directory lives in python path.
I recently installed python-WikEdDiff package to my system. I understand it is a python extension of the original JavaScript WikEdDiff tool. I tried to use it but I couldn't find any documentation for it. I am stuck at using WikEdDiff.diff(). I wish to use the other functions of this class, such as getFragments() and others, but on checking, it shows the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.4/dist-packages/WikEdDiff/diff.py", line 1123, in detectBlocks
self.getSameBlocks()
File "/usr/local/lib/python3.4/dist-packages/WikEdDiff/diff.py", line 1211, in getSameBlocks
while j is not None and self.oldText.tokens[j].link is None:
IndexError: list index out of range
On checking, I found out that the tokens[] structure in the object remains empty whereas it should have been initialized.
Is there an initialize function that I need to call apart from the default constructor? Or is it something to do with the `WikEdDiffConfig' config structure I passed to the constructor?
You get this error because the WikEdDiff object was cleared internally inside diff(), as shown in this section of the code:
def diff( self, oldString, newString ):
...
# Free memory
self.newText.tokens.clear()
self.oldText.tokens.clear()
# Assemble blocks into fragment table
fragments = self.getDiffFragments()
# Free memory
self.blocks.clear()
self.groups.clear()
self.sections.clear()
...
return fragments
If you just need the fragments, use the returned variable of diff() like this:
import WikEdDiff as WED
config=WED.WikEdDiffConfig()
w = WED.WikEdDiff(config)
f = w.diff("abc", "efg")
# do whatever you want with f, but don't use w
print(' '.join([i.text+i.type for i in f]))
# outputs '{ [ (> abc- ) abc< efg+ ] }'
I am trying to run a python project. Some part of the code calls a serializer with the following code:
try:
fo = open(data_file, "rb")
except IOError:
print "Couldn't open data file: %s" % data_file
return
try:
myobject = pickle.load(fo)
except:
fo.close()
print "Unexpected error:", sys.exc_info()[0]
raise
fo.close()
return myobject
When this part of the code is run, I get an error on
myobject = pickle.load(fo)
The error is:
myobject = pickle.load(fo)
File "/cs/local/lib/pkg/epd-7.3.1/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/cs/local/lib/pkg/epd-7.3.1/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/cs/local/lib/pkg/epd-7.3.1/lib/python2.7/pickle.py", line 1090, in load_global
klass = self.find_class(module, name)
File "/cs/local/lib/pkg/epd-7.3.1/lib/python2.7/pickle.py", line 1124, in find_class
__import__(module)
ImportError: No module named label
I have looked at : Import Error using cPickle in Python
but I cant use any of the solutions because:
"You can open the file binarily and replace options with the module you replaced the old module options with." => I dont know which binary file the solution is refering to. I dont seem to have any binary file in my package.
In my package, I dont have a module named label to import it.
I'm very lost and I would appreciate any help, any suggestions.
When pickle serializes an object, it serializes modules by reference. So if you have a function or some other python object that has a call stack, it might refer to the module label, which cannot be found. If you have a serialized class, class instance, function, or especially a closure… you might have a import label in the source code used to build that object. a pickled object is a set of instructions for python for how to turn binary bits of information into a python object. if some of the bits are missing, such as a module… (pickle again stores this by reference), then your unpickle will fail.
You could either try to install the label module, or you could ask the party who serialized the object to serialize it with a serializer that serializes the module itself instead of doing so by reference. I think you can do this with the dill serializer.
If the person who serialized the object had label in their globals, and there was a closure being serialized, pickle includes everything in globals… so it might not even be relevant, but you'd need it do unserialize the object. You could also ask for a re-pickle by a serializer that is more cautious about including globals, like dill or cloudpickle.
That's basically what Import Error using cPickle in Python is saying in a less general way.