Best way to write understandable and Python-friendly code [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I have this code
def testing1(terms, request):
dat = datetime.now(pytz.timezone(geo_timezone(request)))
__start = terms['year']+'-'+terms['month']+'-'+terms['day']+'T'+'00:00:00'+dat.strftime('%z')[:-2]+':'+dat.strftime('%z')[-2:]
__end = terms['year']+'-'+terms['month']+'-'+terms['day']+'T'+'23:59:59'+dat.strftime('%z')[:-2]+':'+dat.strftime('%z')[-2:]
return __start, __end
testing({"month":12,"day":1, "year":"2015"}, request)
But I have a interrogant, whats is the best way to write this code, readable and friendly for the others programers?
Any suggestion for write code extensive in one line like this?
This suggestion is readable?
def testing2(terms, request):
dat = datetime.now(pytz.timezone(geo_timezone(request)))
__start = terms['year'] + '-' + terms['month'] + '-' + terms['day'] + \
'T' + '00:00:00' + dat.strftime('%z')[:-2] + ':' + dat.strftime('%z')[-2:]
__end = terms['year'] + '-' + terms['month'] + '-' + terms['day'] + \
'T' + '23:59:59' + dat.strftime('%z')[:-2] + ':' + dat.strftime('%z')[-2:]
return __start, __end

The only hard part to read is where you build your string so I would use .format(). This way you can see the resulting layout and then all of the corresponding entries.
__start = '{}-{}-{}T00:00:00{}:{}'.format(terms['year'],
terms['month'],
terms['day'],
dat.strftime('%z')[:-2],
dat.strftime('%z')[-2:])
__end = '{}-{}-{}T23:59:59{}:{}'.format(terms['year'],
terms['month'],
terms['day'],
dat.strftime('%z')[:-2],
dat.strftime('%z')[-2:])

Personally, I'd go with that second block and call it a day. If you want, you could try aligning it into groups, or messing with str.format():
__start = terms['year'] + '-' + terms['month'] + '-' + terms['day'] + \
'T00:00:00' + \
dat.strftime('%z')[:-2] + ':' + dat.strftime('%z')[-2:]
__end = terms['year'] + '-' + terms['month'] + '-' + terms['day'] + \
'T23:59:59' + \
dat.strftime('%z')[:-2] + ':' + dat.strftime('%z')[-2:]
__start = ('{}-{}-{}'.format(terms['year'], terms['month'], terms['day']) +
'T00:00:00' +
'{}:{}'.format(dat.strftime('%z')[:-2], dat.strftime('%z')[-2:]))
__end = ('{}-{}-{}'.format(terms['year'], terms['month'], + terms['day']) +
'T23:59:59' +
'{}:{}'.format(dat.strftime('%z')[:-2], dat.strftime('%z')[-2:]))

You can try something like :
__start = ''.join([terms['year'], '-',
terms['month'], '-',
terms['day'], 'T',
'00:00:00',
dat.strftime('%z')[:-2], ':',
dat.strftime('%z')[-2:]
])
Parenthesis, brackets and braces will help you to keep your lines of code < 80 characters
(and here the join method of string objects is more efficient than operator +)
As your post is about coding style it's hard to not mention the PEP8 if you don't know it already.

Related

(pyparsing) delimitedList does not work as expected

I have a stringized array that I am receiving from an external system. It is stripped of quotes and separated by a comma and a space.
I'm trying to use pyparsing, but I'm only getting the first element of the array. How do I specify that a word must end in alphanumeric ?
value = '[AaAa=Aaa_xx_12,Bxfm=djfn_13, ldfjk=ddd,ttt=ddfs_ddfj_99]'
LBR, RBR = map(pp.Suppress, "[]")
qs = pp.Word(pp.alphas, pp.alphanums + pp.srange("[_=,]"))
qsList = LBR + pp.delimitedList(qs, delim=', ') + RBR
print(value)
print(qsList.parseString(value).asList())
[AaAa=Aaa_xx_12,Bxfm=djfn_13, ldfjk=ddd,ttt=ddfs_ddfj_99]
# pyparsing.exceptions.ParseException: Expected ']', found 'ldfjk' (at char 30), (line:1, col:31)
BR
Thanks for the mental support :D
LBR, RBR = map(pp.Suppress, "[]")
element = pp.Word(pp.alphanums) + pp.Literal('=') + pp.Word(pp.alphanums + pp.srange("[_]"))
qs = pp.Combine(element + pp.OneOrMore(pp.Optional(pp.Literal(',')) + element))
qsList = LBR + pp.delimitedList(qs, delim= ', ') + RBR
print(value)
print(qsList.parseString(value).asList())
#[AaAa=Aaa_xx_12,Bxfm=djfn_13, ldfjk=ddd,ttt=ddfs_ddfj_99]
#['AaAa=Aaa_xx_12,Bxfm=djfn_13', 'ldfjk=ddd,ttt=ddfs_ddfj_99']

How to dynamically create a JSON string?

I am trying to create a JSON string that I can send in a PUT request but build it dynamically. For example, once I am done, I'd like the string to look like this:
{
"request-id": 1045058,
"db-connections":
[
{
"db-name":"Sales",
"table-name":"customer"
}
]
}
I'd like to use constants for the keys, for example, for request-id, I'd like to use CONST_REQUEST_ID. So the keys will be,
CONST_REQUEST_ID = "request-id"
CONST_DB_CONNECTIONS = "db_connections"
CONST_DB_NAME = "db-name"
CONST_TABLE_NAME = "table-name"
The values for the keys will be taken from various variables. For example we can take value "Sales" from a var called dbname with the value "Sales".
I have tried json.load and getting exception.
Help would be appreciated please as I am a bit new to Python.
Create a normal python dictionary, then convert it to JSON.
raw_data = {
CONST_DB_NAME: getDbNameValue()
}
# ...
json_data = json.dumps(raw_data)
# Use json_data in your PUT request.
You can concat the string using + with variables.
CONST_REQUEST_ID = "request-id"
CONST_DB_CONNECTIONS = "db_connections"
CONST_DB_NAME = "db-name"
CONST_TABLE_NAME = "table-name"
request_id = "1045058"
db_name = "Sales"
table_name = 'customer'
json_string = '{' + \
'"' + CONST_REQUEST_ID + '": ' + request_id \
+ ',' + \
'"db-connections":' \
+ '[' \
+ '{' \
+ '"' + CONST_DB_NAME +'":"' + db_name + '",' \
+ '"' + CONST_TABLE_NAME + '":"' + table_name + '"' \
+ '}' \
+ ']' \
+ '}'
print json_string
And this is the result
python st_ans.py
{"request-id": 1045058,"db-connections":[{"db-name":"Sales","table-name":"customer"}]}

Working code but pycharm marks tmF and tmR in list as "local variable referenced before assignment", why is this?

I've only recently started programming so there may be a simple answer to this question but I couldn't find it on here. My code works fine for what I want to do but as I am new to this I want to get into the practice of writing good readable code. I am using PyCharm and I noticed it marked some of the code below as not defined. I understand a little about global vs local variables and I guess it has something to do with this but I can't work out why this part of the code works at all if this is the case.
if len(primerF) < 14:
tmF = (no_A_F + no_T_F) * 2 + (no_C_F + no_G_F) * 4
float_tmF = float(tmF)
print("Forward primer tm: " + str(float_tmF))
elif len(primerR) > 13:
tmR = 64.9 + 41*(no_C_R + no_G_R - 16.4) / (no_A_R + no_T_R + no_G_R +
no_C_R)
print("Reverse primer tm: " + str(tmR))
if len(primerR) < 14:
tmR = (no_A_R + no_T_R) * 2 + (no_C_R + no_G_R) * 4
print("Reverse primer tm: " + str(tmR))
elif len(primerR) > 13:
tmR = 64.9 + 41*(no_C_R + no_G_R - 16.4) / (no_A_R + no_T_R + no_G_R +
no_C_R)
print("Reverse primer tm: " + str(tmR))
gc_F = (no_G_F + no_C_F)
gc_content_F = float(gc_F) / forward_length * 100
print("Forward GC content: " + str(gc_content_F) + "%")
gc__R = (no_G_R + no_C_R)
gc_content_R = float(gc__R) / reverse_length * 100
print("Reverse GC content: " + str(gc_content_R) + "%")
This block here is marked as name not defined and if I click on the bubble it says: "This inspection warns about local variables referenced before assignment".
list_tm = [**tmF**, **tmR**]
high_tm = max(list_tm)
low_tm = min(list_tm)
You're setting tmF and tmR in conditional blocks that do not cover all possibilities. For example, if primerF is >= 14, tmF will never be set before the list_tm = [tmF, tmR] statement. This will result in a runtime error, which pycharm is warning you about.
One way to fix this is to set default values of tmF and tmR at the top of your code, or to have full conditional coverage by setting tmF and tmR in else (not just elif) blocks.

Querying a shading node Maya Python

I am currently having a problem where i want to query the 'inputX' of a multiplyDivide Node in maya and put the queried number into the 'inputX' of another multiplyDivide node.
The script currently makes an stretchy IK set up for an arm. Using a distanceBetween the shoulder and the wrist (at a certain point, which is what i want to query) the bones would then stretch. So obviously, I don't want to connect the two together.
def stretchyIK(firstJointStore, lastJointStore, side, limb):
GlobalMoveRig = cmds.rename ('GlobalMove_Grp_01')
locFirstJoint = cmds.spaceLocator (n='Loc_' + firstJointStore + '_0#')
locLastJoint = cmds.spaceLocator (n='Loc_' + lastJointStore + '_0#')
pointLoc1 = cmds.pointConstraint (side + '_Fk_' + firstJointStore + suffix, locFirstJoint)
pointLoc2 = cmds.pointConstraint (side + '_Fk_' + lastJointStore + suffix, locLastJoint)
cmds.delete (pointLoc1, pointLoc2)
cmds.pointConstraint (side + '_FK_' + firstJointStore + suffix, locFirstJoint)
cmds.pointConstraint (ikCtr, locLastJoint)
cmds.parent (locFirstJoint, locLastJoint, 'Do_Not_Touch')
#Creating Nodes for Stretchy IK
IkStretch_DisNode = cmds.shadingNode ('distanceBetween', asUtility=True, n='DistBet_IkStretch_' + side + limb + '_#')
cmds.connectAttr (locFirstJoint[0] + '.translate', IkStretch_DisNode + '.point1')
cmds.connectAttr (locLastJoint[0] + '.translate', IkStretch_DisNode + '.point2')
IkStretch_DivNode = cmds.shadingNode ('multiplyDivide', asUtility=True, n='Div_IkStretch_' + side + limb + '_#')
cmds.setAttr (IkStretch_DivNode + '.operation', 2)
input = cmds.connectAttr (IkStretch_DisNode + '.distance', IkStretch_DivNode + '.input1.input1X') ########HELP NEEDED HERE
cmds.setAttr (ikCtr + '.translateX', 2)
IkStretch_MultNode = cmds.shadingNode ('multiplyDivide', asUtility=True, n='Mult_IkStretch_' + side + limb + '_#')
cmds.setAttr (IkStretch_MultNode + '.input1X', IkStretch_DivNode + '.input1.input1X')#WAIT FOR PAUL
cmds.connectAttr (GlobalMoveRig + '.scaleY', IkStretch_MultNode + '.input2X')
cmds.connectAttr (IkStretch_MultNode + '.outputX', IkStretch_DivNode + '.input2X')
IkStretch_Cond_Equ = cmds.shadingNode ('condition', asUtility=True, n='Cond_Equ_IkStretch_' + side + limb + '_#')
IkStretch_Cond_GrtEqu = cmds.shadingNode ('condition', asUtility=True, n='Cond_GrtEqu_IkStretch_' + side + limb + '_#')
cmds.setAttr (IkStretch_Cond_GrtEqu + '.operation', 3)
cmds.connectAttr (ikCtr + '.Enable', IkStretch_Cond_Equ + '.firstTerm')
cmds.setAttr (IkStretch_Cond_Equ + '.secondTerm', 1)
cmds.connectAttr (IkStretch_DisNode + '.distance', IkStretch_Cond_GrtEqu + '.firstTerm')
cmds.connectAttr (IkStretch_MultNode + '.outputX', IkStretch_Cond_GrtEqu + '.secondTerm')
cmds.connectAttr (IkStretch_DivNode + '.outputX', IkStretch_Cond_GrtEqu + '.colorIfTrueR')
cmds.connectAttr (IkStretch_Cond_GrtEqu + '.outColorR', IkStretch_Cond_Equ + '.colorIfTrueR')
cmds.connectAttr (IkStretch_Cond_GrtEqu + '.outColorR', side + '_Ik_' + secondJointStore + suffix + '.scaleX')
cmds.connectAttr (IkStretch_Cond_GrtEqu + '.outColorR', side + '_Ik_' + firstJointStore + suffix + '.scaleX')
Yes, your error makes perfect sense... The attribute you're looking for is actually just '.input1X' rather than '.input1.input1X'.
I know, that isn't very clear, but you'll know in the future. An easy way of figuring out stuff like this, by the way, is manually connecting stuff in Maya and seeing the MEL output in the script editor. You'll get the real deal every time, and translating that stuff to Python afterwards is quick.
So:
cmds.connectAttr(IkStretch_DisNode + '.distance', IkStretch_DivNode + '.input1X')
By the way, I'm not sure why you were assigning the result to input. I admit I'm not sure what that would return, but I don't see how it could be any useful!
Additionally: To answer your direct question, you can use getattr to query the value.
cmds.setAttr(
IkStretch_MultNode + '.input1X',
cmds.getattr(IkStretch_DivNode + '.input1X')
)
In my case, the variable being assigned to be set as the new attribute value was not being evaluated properly. setAttr interpreted the variable value as text, even though the value was input as a float value.
So, I simply assigned the variable and set it to float the variable within the command. In my case, I did the following:
cmds.setAttr(Node + '.input1X', float(variable))

Geotagging JPEGs with pyexiv2

I am geotagging JPEGs using the pyexiv2 Python module using code I found in another SO answer (see: What is the best way to geotag jpeg-images using Python?) and I have a question about the GPSTag value.
The code given in the answer has the following lines:
exiv_image["Exif.Image.GPSTag"] = 654
exiv_image["Exif.GPSInfo.GPSMapDatum"] = "WGS-84"
exiv_image["Exif.GPSInfo.GPSVersionID"] = '2 0 0 0'
I have looked at the Exiv2 documentation and found descriptions of GPSTag, GPSMapDatum, and GPSVersionID but am still confused about the value for GPSTag.
From the documentation it says:
A pointer to the GPS Info IFD. The Interoperability structure of the GPS Info IFD, like that of Exif IFD, has no image data.
This description does not really explain how to determine what value to use and I have not been able to find a better description of GPSTag online.
So my questions are:
Given a new image, how do you determine the value of Exif.Image.GPSTag?
Why is the code sample using a value of 654 (this may be answered by question one)?
Thanks for your help.
Best way to geotag photos using pyexiv2 is definitely with my program, GottenGeography ;-)
But seriously though, if you're wanting to access GPS data from pyexiv2, that code looks like this:
GPS = 'Exif.GPSInfo.GPS'
try:
self.latitude = dms_to_decimal(
*self.exif[GPS + 'Latitude'].value +
[self.exif[GPS + 'LatitudeRef'].value]
)
self.longitude = dms_to_decimal(
*self.exif[GPS + 'Longitude'].value +
[self.exif[GPS + 'LongitudeRef'].value]
)
except KeyError:
pass
try:
self.altitude = float(self.exif[GPS + 'Altitude'].value)
if int(self.exif[GPS + 'AltitudeRef'].value) > 0:
self.altitude *= -1
except KeyError:
pass
And writing looks like this:
self.exif[GPS + 'AltitudeRef'] = '0' if self.altitude >= 0 else '1'
self.exif[GPS + 'Altitude'] = Fraction(self.altitude)
self.exif[GPS + 'Latitude'] = decimal_to_dms(self.latitude)
self.exif[GPS + 'LatitudeRef'] = 'N' if self.latitude >= 0 else 'S'
self.exif[GPS + 'Longitude'] = decimal_to_dms(self.longitude)
self.exif[GPS + 'LongitudeRef'] = 'E' if self.longitude >= 0 else 'W'
self.exif[GPS + 'MapDatum'] = 'WGS-84'
With these support functions:
class Fraction(fractions.Fraction):
"""Only create Fractions from floats.
>>> Fraction(0.3)
Fraction(3, 10)
>>> Fraction(1.1)
Fraction(11, 10)
"""
def __new__(cls, value, ignore=None):
"""Should be compatible with Python 2.6, though untested."""
return fractions.Fraction.from_float(value).limit_denominator(99999)
def dms_to_decimal(degrees, minutes, seconds, sign=' '):
"""Convert degrees, minutes, seconds into decimal degrees.
>>> dms_to_decimal(10, 10, 10)
10.169444444444444
>>> dms_to_decimal(8, 9, 10, 'S')
-8.152777777777779
"""
return (-1 if sign[0] in 'SWsw' else 1) * (
float(degrees) +
float(minutes) / 60 +
float(seconds) / 3600
)
def decimal_to_dms(decimal):
"""Convert decimal degrees into degrees, minutes, seconds.
>>> decimal_to_dms(50.445891)
[Fraction(50, 1), Fraction(26, 1), Fraction(113019, 2500)]
>>> decimal_to_dms(-125.976893)
[Fraction(125, 1), Fraction(58, 1), Fraction(92037, 2500)]
"""
remainder, degrees = math.modf(abs(decimal))
remainder, minutes = math.modf(remainder * 60)
return [Fraction(n) for n in (degrees, minutes, remainder * 60)]
Although I am currently working on an alternative to pyexiv2 that uses GObject introspection to access the exiv2 library much more directly, called GExiv2, and would love to have some feedback on it. Both gexiv2 and pyexiv2 are wrappers around the same exiv2 library, but the difference is that pyexiv2 is a very large project with lots of glue, only works in python, and is on the brink of abandonment*; whereas gexiv2 is light and nimble, accessible from any programming language, and is well maintained thanks to it's use by Shotwell.
Hope this helps!
* pyexiv2's author, Olivier Tilloy, has asked me for help with maintainership as he no longer has much time
My version, a little lengthy...
from fractions import Fraction
import pyexiv2
try:
metadata = pyexiv2.metadata.ImageMetadata(image_file)
metadata.read();
thumb = metadata.exif_thumbnail
try:
latitude = metadata.__getitem__("Exif.GPSInfo.GPSLatitude")
latitudeRef = metadata.__getitem__("Exif.GPSInfo.GPSLatitudeRef")
longitude = metadata.__getitem__("Exif.GPSInfo.GPSLongitude")
longitudeRef = metadata.__getitem__("Exif.GPSInfo.GPSLongitudeRef")
latitude = str(latitude).split("=")[1][1:-1].split(" ");
latitude = map(lambda f: str(float(Fraction(f))), latitude)
latitude = latitude[0] + u"\u00b0" + latitude[1] + "'" + latitude[2] + '"' + " " + str(latitudeRef).split("=")[1][1:-1]
longitude = str(longitude).split("=")[1][1:-1].split(" ");
longitude = map(lambda f: str(float(Fraction(f))), longitude)
longitude = longitude[0] + u"\u00b0" + longitude[1] + "'" + longitude[2] + '"' + " " + str(longitudeRef).split("=")[1][1:-1]
latitude_value = dms_to_decimal(*metadata.__getitem__("Exif.GPSInfo.GPSLatitude").value + [metadata.__getitem__("Exif.GPSInfo.GPSLatitudeRef").value]);
longitude_value = dms_to_decimal(*metadata.__getitem__("Exif.GPSInfo.GPSLongitude").value + [metadata.__getitem__("Exif.GPSInfo.GPSLongitudeRef").value]);
print "--- GPS ---"
print "Coordinates: " + latitude + ", " + longitude
print "Coordinates: " + str(latitude_value) + ", " + str(longitude_value)
print "--- GPS ---"
except Exception, e:
print "No GPS Information!"
#print e
# Check for thumbnail
if(thumb.data == ""):
print "No thumbnail!"
except Exception, e:
print "Error processing image..."
print e;

Categories