Skip to content

Update xlsw.py #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 26, 2021
Merged

Update xlsw.py #48

merged 1 commit into from
Sep 26, 2021

Conversation

vinraspa
Copy link
Contributor

@vinraspa vinraspa commented Sep 15, 2021

added 'timedelta' support

With your PR, here is a check list:

  • Has test cases written?
  • Has all code lines tested?
  • Has make format been run?
  • Please update CHANGELOG.yml(not CHANGELOG.rst)
  • Has fair amount of documentation if your change is complex
  • Agree on NEW BSD License for your contribution

added 'timedelta' support
@chfw
Copy link
Member

chfw commented Sep 22, 2021

Do you want to add one unit test ?

@vinraspa
Copy link
Contributor Author

Sorry, I am new to git(hub), pull requests and all.
I do not want specifically to add a unit test, but actually not sure of what it is...

@codecov-commenter
Copy link

codecov-commenter commented Sep 25, 2021

Codecov Report

Merging #48 (473ee14) into dev (26b665c) will decrease coverage by 0.98%.
The diff coverage is 12.50%.

Impacted file tree graph

@@            Coverage Diff             @@
##              dev      #48      +/-   ##
==========================================
- Coverage   98.40%   97.42%   -0.99%     
==========================================
  Files          13       13              
  Lines         690      698       +8     
==========================================
+ Hits          679      680       +1     
- Misses         11       18       +7     
Impacted Files Coverage Δ
pyexcel_xls/xlsw.py 87.09% <12.50%> (-11.06%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 26b665c...473ee14. Read the comment docs.

@chfw chfw merged commit 23fc6a5 into pyexcel:dev Sep 26, 2021
@chfw
Copy link
Member

chfw commented Sep 26, 2021

Thanks for PR. I will cover the unit test.

@vinraspa
Copy link
Contributor Author

Fine. Thank you.

@chfw
Copy link
Member

chfw commented Oct 2, 2021

I am afraid that timedelta cannot be supported because it cannot pass the unit test.

https://xlrd.readthedocs.io/en/latest/api.html#xlrd.xldate.xldate_from_time_tuple where hour must be < 24h.

@chfw
Copy link
Member

chfw commented Oct 2, 2021

@chfw
Copy link
Member

chfw commented Oct 2, 2021

How do you use timedelta with this package?

@vinraspa
Copy link
Contributor Author

vinraspa commented Oct 2, 2021

OK, I found the problem and a way to fix it. I got something wrong. It is clearer now.
Sorry, I did not test my PR with timedelta with h>24...
Furthermore, I deleted personal repo so I am not able to push the fix (at least I don't know how to).
What do you recommend? Should I make a new PR with the fix?

@vinraspa
Copy link
Contributor Author

vinraspa commented Oct 2, 2021

Actually, xlrd.xldate.xldate_from_time_tuple() is not needed.
We just need to convert timedelta to a fraction of day.

value = value.days + value.seconds / 86_400

Furthermore, DEFAULT_TIME_FORMAT = "HH:MM:SS" is not good.
We need to create another one: I suggest DEFAULT_LONGTIME_FORMAT = "[HH]:MM:SS"

Finally:

            elif isinstance(value, datetime.timedelta):
                value = value.days + value.seconds / 86_400
                style = XFStyle()
                style.num_format_str = DEFAULT_LONGTIME_FORMAT

The whole file:

"""
    pyexcel_xlsw
    ~~~~~~~~~~~~~~~~~~~

    The lower level xls file format handler using xlwt

    :copyright: (c) 2016-2020 by Onni Software Ltd
    :license: New BSD License
"""
import datetime

import xlrd
from xlwt import XFStyle, Workbook
from pyexcel_io import constants
from pyexcel_io.plugin_api import IWriter, ISheetWriter

DEFAULT_DATE_FORMAT = "DD/MM/YY"
DEFAULT_TIME_FORMAT = "HH:MM:SS"
DEFAULT_LONGTIME_FORMAT = "[HH]:MM:SS"
DEFAULT_DATETIME_FORMAT = "%s %s" % (DEFAULT_DATE_FORMAT, DEFAULT_TIME_FORMAT)
EMPTY_SHEET_NOT_ALLOWED = "xlwt does not support a book without any sheets"


class XLSheetWriter(ISheetWriter):
    """
    xls sheet writer
    """

    def __init__(self, xls_book, xls_sheet, sheet_name):
        if sheet_name is None:
            sheet_name = constants.DEFAULT_SHEET_NAME
        self._xls_book = xls_book
        self._xls_sheet = xls_sheet
        self._xls_sheet = self._xls_book.add_sheet(sheet_name)
        self.current_row = 0

    def write_row(self, array):
        """
        write a row into the file
        """
        for i, value in enumerate(array):
            style = None
            tmp_array = []
            if isinstance(value, datetime.datetime):
                tmp_array = [
                    value.year,
                    value.month,
                    value.day,
                    value.hour,
                    value.minute,
                    value.second,
                ]
                value = xlrd.xldate.xldate_from_datetime_tuple(tmp_array, 0)
                style = XFStyle()
                style.num_format_str = DEFAULT_DATETIME_FORMAT
            elif isinstance(value, datetime.timedelta):
                value = value.days + value.seconds / 86_400
                style = XFStyle()
                style.num_format_str = DEFAULT_LONGTIME_FORMAT
            elif isinstance(value, datetime.date):
                tmp_array = [value.year, value.month, value.day]
                value = xlrd.xldate.xldate_from_date_tuple(tmp_array, 0)
                style = XFStyle()
                style.num_format_str = DEFAULT_DATE_FORMAT
            elif isinstance(value, datetime.time):
                tmp_array = [value.hour, value.minute, value.second]
                value = xlrd.xldate.xldate_from_time_tuple(tmp_array)
                style = XFStyle()
                style.num_format_str = DEFAULT_TIME_FORMAT
            if style:
                self._xls_sheet.write(self.current_row, i, value, style)
            else:
                self._xls_sheet.write(self.current_row, i, value)
        self.current_row += 1

    def close(self):
        pass


class XLSWriter(IWriter):
    """
    xls writer
    """

    def __init__(
        self,
        file_alike_object,
        _,  # file_type not used
        encoding="ascii",
        style_compression=2,
        **keywords
    ):
        self.file_alike_object = file_alike_object
        self.work_book = Workbook(
            style_compression=style_compression, encoding=encoding
        )

    def create_sheet(self, name):
        return XLSheetWriter(self.work_book, None, name)

    def write(self, incoming_dict):
        if incoming_dict:
            IWriter.write(self, incoming_dict)
        else:
            raise NotImplementedError(EMPTY_SHEET_NOT_ALLOWED)

    def close(self):
        """
        This call actually save the file
        """
        self.work_book.save(self.file_alike_object)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants