Re: [Tutor] Python 3: string to decimal conversion

2016-05-22 Thread Steven D'Aprano
On Sat, May 21, 2016 at 01:34:20PM -0500, Saidov wrote:

> "decimal.InvalidOperation was unhandled by user code
> Message: []"
> 
> *Question: *I tried looking up the meaning of this error, but couldn't find
> anything on the internet. *Can someone help me understand what's wrong with
> my code?*

https://duckduckgo.com/html/?q=decimal+InvalidOperation+python

will take you to the docs for Python 2. Changing the URL to version 3 
gives us:

https://docs.python.org/3/library/decimal.html

and searching for InvalidOperation gives us:

https://docs.python.org/3/library/decimal.html#decimal.InvalidOperation

which is not a lot of help as it only lists *some* of the things which 
will lead to that error, but we can try it at the interactive 
interpreter:

py> import decimal
py> decimal.Decimal("25")
Decimal('25')
py> decimal.Decimal("25x")
Traceback (most recent call last):
  File "", line 1, in 
decimal.InvalidOperation: []


So the problem here is that when you call Decimal() with an invalid 
argument, you are expecting a ValueError, but Python raises 
decimal.InvalidOperation instead:

> try:
> expenses[ts.Date(row[0]).month] += decimal.Decimal(row[4])
> except ValueError:
> pass


-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Python 3: string to decimal conversion

2016-05-22 Thread US
Thank you all for the useful feedback. I am new to programming so bear
with me while I learn the rules...


I have run Cameron's code to print the values and have the traceback
results. please see below.



-Original Message-
From: c...@zip.com.au [mailto:c...@zip.com.au]
Sent: Saturday, May 21, 2016 10:32 PM
To: Saidov 
Cc: tutor@python.org
Subject: Re: [Tutor] Python 3: string to decimal conversion

Hi Saidov,

I'm going to reply to your post inline, as that is the etiquette here and
in many technical mailing lists.

On 21May2016 13:34, Saidov  wrote:
>I am working on a piece of python code that's supposed to help me
>manage a
>budget:
>1. Read a banking statement
>2. Categorize expenses and income by month and by type 3. Print out a
>report comparing the projected expenses/income with actual numbers.

Thank you for providing your problem's context.

>*File characteristics:*
>Banking statement in a csv file format.
>contents: 5 columns, 1st column= date, 4 column=expenses date format:
>mm/dd/, type: string expenses format: ($0.00), type: string income
>format: $0.00, type: string
>
>*Python Version: 3.5 (64 bit)*
>IDE:Microsoft Visual Studio Community 2015 Version 14.0.25123.00 Update
>2
>
>Python Tools for Visual Studio   2.2.40315.00
>Python Tools for Visual Studio provides IntelliSense, projects,
>templates, Interactive windows, and other support for Python developers.

And this level of detail is very welcome.

>*Problem:*
> I want to convert expense/income values into a decimal form so I could
>sum them into appropriate buckets according to the month in which they
>occur. I am getting the following error message when I run my code:
>
>"decimal.InvalidOperation was unhandled by user code
>Message: []"

Please always provide the full traceback which accompanied the exception
report; there should be a list of code lines indicating the call stack
where the error occurred. This provides valuable context for figuring out
where in your code to look for issues.

Absent that context, I will have a guess at where this might be occurring:

[...]
>files =['export.csv']
>with open("budgetfile.csv","wt") as fw:
>writer = csv.writer(fw)
>for file in files:
>with open(file) as csvfile:
>records = csv.reader(csvfile, quoting=csv.QUOTE_NONE)
[...]
>for row in records:
[...]
>try:
>expenses[ts.Date(row[0]).month] +=
decimal.Decimal(row[4])
>except ValueError:
>pass

I would guess that this:

  decimal.Decimal(row[4])

is the source of your error; it seems to be the only place where you
actually convert a string into a Decimal. I would guess that when handed a
bad string this raises decimal.ConversionSyntax instead of a ValueError.

I suggest that you print out the value of row[4] before the "try"
statement:

  print("row[4] =", repr(row[4]))

Note the use of repr: it gets you better detail about the value of the
string.

Thank you for a well presented question.

Finally, please try to post in plain text instead of rich text; this is a
plain text list and if you post in rich text or HTML (a) some hinting you
have have povided like coloured text will not be presented to readers and
(b) some things, particularly code, and be presented visually mangled,
which makes things hard to read and debug.

-
+ decimal  module
+ expenses {1: Decimal('0'), 2: Decimal('0'), 3: Decimal('0'), 4:
Decimal('0'), 5: Decimal('0'), 6: Decimal('0'), 7: Decimal('0'), 8:
Decimal('0'), 9: Decimal('0'), 10: Decimal('0'), 11: Decimal('0'), 12:
Decimal('0')} dict
row[0] '"1/1/2016"' str
row[4] '""' str
+ ts 
module

ipython traceback:

row[4]= ' "" '

Traceback (most recent call last):
  File "C:\mypath\visual studio
2015\Projects\Budget\Budget\Budget.py", line 28, in 
expenses[ts.Date(row[0]).month] += decimal.Decimal(row[4])
decimal.InvalidOperation: []


I think the problem may be caused by an empty string value that is
passed to decimal.Decimal function. The csv file contains some empty
cells and I wanted the code to ignore them. That's why I had the
ValueError exception.



--


Cheers,
Cameron Simpson 
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Python 3: string to decimal conversion

2016-05-22 Thread Alan Gauld via Tutor
On 22/05/16 14:19, US wrote:

>>with open(file) as csvfile:
>>records = csv.reader(csvfile, quoting=csv.QUOTE_NONE)
> [...]
>>for row in records:
> [...]
>>try:
>>expenses[ts.Date(row[0]).month] +=
> decimal.Decimal(row[4])
>>except ValueError:
>>pass

> I think the problem may be caused by an empty string value that is
> passed to decimal.Decimal function. The csv file contains some empty
> cells and I wanted the code to ignore them. That's why I had the
> ValueError exception.

If you know you are going to get some invalid data in your loop you
should test for it before the operation and use 'continue' to force the
loop to start the next iteration.  You could still catch the invalid
operation  error, just in case... Although, if you don't expect it and
don't know how to handle it then it's probably better to let Python just
do  its thing and give you the traceback.

Like this:

  with open(file) as csvfile:
 records = csv.reader(csvfile, quoting=csv.QUOTE_NONE)
   #...
   for row in records:
 if not row[4]:
 continue# coz its empty
 else:
 expenses[ts.Date(row[0]).month] += decimal.Decimal(row[4])

HTH
-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Python 3: string to decimal conversion

2016-05-22 Thread cs

On 22May2016 08:19, Saidov  wrote:

Thank you all for the useful feedback. I am new to programming so bear
with me while I learn the rules...

I have run Cameron's code to print the values and have the traceback
results. please see below.

[...]

   for row in records:

[...]

   try:
   expenses[ts.Date(row[0]).month] +=

decimal.Decimal(row[4])

   except ValueError:
   pass

[...]

I suggest that you print out the value of row[4] before the "try"
statement:
 print("row[4] =", repr(row[4]))

[...]
+ decimal  
module

+ expenses {1: Decimal('0'), 2: Decimal('0'), 3: Decimal('0'), 4:
Decimal('0'), 5: Decimal('0'), 6: Decimal('0'), 7: Decimal('0'), 8:
Decimal('0'), 9: Decimal('0'), 10: Decimal('0'), 11: Decimal('0'), 12:
Decimal('0')} dict
row[0] '"1/1/2016"' str
row[4] '""' str
+ ts 
module

ipython traceback:

row[4]= ' "" '

Traceback (most recent call last):
 File "C:\mypath\visual studio
2015\Projects\Budget\Budget\Budget.py", line 28, in 
   expenses[ts.Date(row[0]).month] += decimal.Decimal(row[4])
decimal.InvalidOperation: []

I think the problem may be caused by an empty string value that is
passed to decimal.Decimal function. The csv file contains some empty
cells and I wanted the code to ignore them. That's why I had the
ValueError exception.


I have two observations here:

Your strings in row[4] are not empty. If that output is repr(row[4]) then 
row[4] contains the text:


 ""

That is a two character string consisting of two quote characters.

Normally the csv.reader module will handle that for you, but I see that you 
passed the paramater:


 quoting=csv.QUOTE_NONE

to it when setting it up. It looks to me like your CSV file is a conventional 
one with quotes around string values. By passing csv.QUOTE_NONE you prevent the 
csv module from handling those for you and you get the "raw" column values. So 
a column with an empty string is probably written as "" in the file.


Could you show is the first line or so from your CSV file? That should tell us 
and you whether the file is "bare" comma separate values or the far more common 
quoted format.


If it is the quoted format, just remove the "quoting=csv.QUOTE_NONE" parameter 
altogether - the default for the csv module is quoted and it is _usually_ what 
is wanted. Of course you need to know one way or the other, so examine the CSV 
file itself.


The other observation is that you're trying to catch ValueError, when plainly 
the Decimal module is raising decimal.InvalidOperation. So you should catch 
that instead.


HOWEVER, just catching it and ignoring that row will _silently_ discard good 
input if you program is incorrect. You should almost always emit an error 
message or perform some other very specific action when you catch an exception.


Alan has suggested that you test specificly for an empty string.

I agree: you should act on exactly what is expected. By blindly catching 
ValueError or decimal.InvalidOperation and not reporting the string that caused 
it to happen you will silently ignore all kinds of unexpected input.


So I would advocate some code like this, similar to Alan's:

 if not row[4]:
   # empty column - we expect this and ignore it
   pass
 else:
   try:
 expenses[ts.Date(row[0]).month] += decimal.Decimal(row[4])
   except decimal.InvalidOperation as e:
 print("unexpected expenses value: %r" % (row[4],))

which will report the offending values, and presumably you expect either an 
empty column or a _valid_ expense value.


Cheers,
Cameron Simpson 
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor