claudep / swiss-qr-bill

A Python library to generate Swiss QR-bill payment slips
MIT License
97 stars 39 forks source link

scissor-character yields encoding-error on Windows #54

Closed celmi closed 3 years ago

celmi commented 3 years ago

I'm quite new at programming, maybe asking stupid questions. I've been trying to run the example codes for a pdf-output but I'm running into this error message: File "C:\Users\MCH\AppData\Local\Programs\Python\Python37\lib\encodings\cp1252.py", line 19, in encode return codecs.charmap_encode(input,self.errors,encoding_table)[0] UnicodeEncodeError: 'charmap' codec can't encode character '\u2702' in position 2754: character maps to <undefined> I suppose it's not an issue of your code, but some problem of mine own, on Windows. From what I understand it. How can I tackle it best? I didn't get anywhere with stack-exchange & co. I appreciate any help.

claudep commented 3 years ago

Thanks for the report. I cannot directly test because I don't own any Windows machine, but if you could provide a full traceback, it would help to see where this is happening.

celmi commented 3 years ago
Traceback (most recent call last):
  File "C:\Users\MCH\qrbill\main.py", line 18, in <module>
    my_bill.as_svg(temp)
  File "C:\Users\MCH\AppData\Local\Programs\Python\Python37\lib\site-packages\qrbill\bill.py", line 449, in as_svg
    dwg.write(file_out)
  File "C:\Users\MCH\AppData\Local\Programs\Python\Python37\lib\site-packages\svgwrite\drawing.py", line 112, in write
    fileobj.write(xml_string)
  File "C:\Users\MCH\AppData\Local\Programs\Python\Python37\lib\tempfile.py", line 481, in func_wrapper
    return func(*args, **kwargs)
  File "C:\Users\MCH\AppData\Local\Programs\Python\Python37\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u2702' in position 2754: character maps to <undefined>

Thanks!

claudep commented 3 years ago

Thanks, now I suppose it's related to how temp is defined in your script. Can you show it as well?

celmi commented 3 years ago

Sure. I basically copied your sample code from github into an empty file and tried to run it (without actually knowing what excatly it means... 😳)

` import tempfile from qrbill.bill import QRBill from svglib.svglib import svg2rlg from reportlab.graphics import renderPDF

if name == 'main': my_bill = QRBill( account='CH5800791123000889012', creditor={ 'name': 'Jane', 'pcode': '1000', 'city': 'Lausanne', 'country': 'CH', }, amount='22.45', ) with tempfile.NamedTemporaryFile(mode='w') as temp: my_bill.as_svg(temp) temp.seek(0) drawing = svg2rlg(temp.name) renderPDF.drawToFile(drawing, "file.pdf") `

claudep commented 3 years ago

Ah, I see! Could you please test with: with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8') as temp:?

If it works I'll update the README accordingly.

celmi commented 3 years ago

Earlier on I'd already been trying this too, because I'd seen something similar being recommended to someone on stackxchange. But it throws another, different error :

Failed to load input file! (Error reading file 'C:\Users\MCH\AppData\Local\Temp\tmphjq_tiew': failed to load external entity "C:\Users\MCH\AppData\Local\Temp\tmphjq_tiew")
Traceback (most recent call last):
  File "C:\Users\MCH\qrbill\main.py", line 21, in <module>
    renderPDF.drawToFile(drawing, "file.pdf")
  File "C:\Users\MCH\AppData\Local\Programs\Python\Python37\lib\site-packages\reportlab\graphics\renderPDF.py", line 290, in drawToFile
    d = renderScaledDrawing(d)
  File "C:\Users\MCH\AppData\Local\Programs\Python\Python37\lib\site-packages\reportlab\graphics\renderbase.py", line 172, in renderScaledDrawing
    renderScale = d.renderScale
AttributeError: 'NoneType' object has no attribute 'renderScale'
claudep commented 3 years ago

Ah, this is already some progress!

Now my suspicion is that the rendering fails because the temporary file cannot be open a second time on Windows (as explained in https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile.)

So instead of using a temporary file, you should use a real file, close it and produce the PDF. Something along these lines:

with open('file.svg', encoding='utf-8', mode='w') as temp:
    my_bill.as_svg(temp)
drawing = svg2rlg('file.svg')
renderPDF.drawToFile(drawing, "file.pdf")

You may want to delete 'file.svg' afterwards.

claudep commented 3 years ago

I have another variant I'd like you to test on Windows (which does not require an intermediate real file):

with tempfile.TemporaryFile(encoding='utf-8', mode='r+') as temp:
    my_bill.as_svg(temp)
    temp.seek(0)
    drawing = svg2rlg(temp)
renderPDF.drawToFile(drawing, "file.pdf")
celmi commented 3 years ago

I've testet the second variant, and it worked just great, thank you so much! 💐 If you would like me to test the first variant too, or help you with other bugs on windows, please let me know. Thank you very much for the kind support.

claudep commented 3 years ago

Thanks for testing. The second version is better anyway. I updated the README sample.

As a final note, I can only encourage you to discover some Linux platform :-)

celmi commented 3 years ago

:-) well, if I was working alone I would have switched the platform a long time ago. But I am responsible not only for myself, but also for my co-workers and so I must better stick with what we've got and not change too many things at once...

claudep commented 3 years ago

I can understand that, it's wise!