Skip to content

Add a "strict" parameter to csv.writer and csv.DictWriter #85002

Open

Description

@ericvsmith
BPO 40825
Nosy @ericvsmith, @serhiy-storchaka, @corona10

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2020-05-30.12:31:33.111>
labels = ['type-feature', '3.10']
title = 'Add a "strict" parameter to csv.writer and csv.DictWriter'
updated_at = <Date 2020-06-02.17:01:51.050>
user = 'https://github.com/ericvsmith'

bugs.python.org fields:

activity = <Date 2020-06-02.17:01:51.050>
actor = 'eric.smith'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = []
creation = <Date 2020-05-30.12:31:33.111>
creator = 'eric.smith'
dependencies = []
files = []
hgrepos = []
issue_num = 40825
keywords = []
message_count = 10.0
messages = ['370380', '370382', '370393', '370402', '370424', '370485', '370486', '370490', '370498', '370613']
nosy_count = 3.0
nosy_names = ['eric.smith', 'serhiy.storchaka', 'corona10']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue40825'
versions = ['Python 3.10']

Activity

  1. ericvsmith commented on May 30, 2020

    @ericvsmith
    MemberAuthor

    Currently, the csv library calls str() on each value it writes. This can lead to surprising behavior, see bpo-40762 for example.

    On the other hand, for writing the documentation says that the values must be strings or numbers.

    The proposed "strict" argument would raise a TypeError if the supplied values are not strings, numbers, or None.

    See

    str = PyObject_Str(field);
    for where str() is called.

    The documentation should be changed to note that None is allowed. Currently, None results in an empty string. I'm not proposing to change this, just document it as one of the allowed types.

    How to check for "value is a number" needs to be decided.

  2. ericvsmith commented on May 30, 2020

    @ericvsmith
    MemberAuthor

    For backward compatibility, strict would have to default to False.

  3. corona10 commented on May 30, 2020

    @corona10
    Member

    I am +1 on with strict mode.
    But I want to hear other core developers opinions.

  4. ericvsmith commented on May 30, 2020

    @ericvsmith
    MemberAuthor

    I guess an isinstance check against numbers.Number would be the best way to check if an argument is a number. I'm not sure how convenient that is from C code.

  5. serhiy-storchaka commented on May 31, 2020

    @serhiy-storchaka
    Member

    There is PyNumber_Check(). It is not direct analog of isinstance(obj, numbers.Number), it checks that the object can be explicitly converted to the real number (int or float). UUID and IPv4Address pass this check.

    As a narrow check we can use isinstance(obj, (str, int, float)). It does not accept Fraction, Decimal and numpy numbers, but it is what such modules like json or plistlib accept.

  6. ericvsmith commented on May 31, 2020

    @ericvsmith
    MemberAuthor

    Losing Decimal would be a problem. I use those a lot in CSV files, and I assume others do, too.

  7. serhiy-storchaka commented on May 31, 2020

    @serhiy-storchaka
    Member

    We can check only nb_index and nb_float. It will include Fraction, Decimal and NumPy numbers and exclude UUID and IPv4Address.

  8. ericvsmith commented on May 31, 2020

    @ericvsmith
    MemberAuthor

    That seems like a good plan.

  9. serhiy-storchaka commented on May 31, 2020

    @serhiy-storchaka
    Member

    Yes, converting Decimal to float can lose precision, so we cannot require this. PyNumber_Check() is already used for QUOTE_NONNUMERIC, so it would be logical to use it in determining that the object is a number in the cvs module.

    But now the problem is with determining what is a "string". There is no way to check whether the object is "string-like", because virtually all objects can be converted to string. The only standard exception is bytes and bytearray for which str() may emit BytesWarning, so this conversion is not reliable. If restrict it only to an instance of str or its subclasses, it may break other user cases, for example writing Path in CVS.

  10. ericvsmith commented on Jun 2, 2020

    @ericvsmith
    MemberAuthor

    I wouldn't have a problem with isinstance(obj, str) for a string check in strict mode. If you want to write something like a Path, convert it to a string yourself. That's exactly the behavior I'd like enforced by strict: only accept numbers and actual strings.

  11. transferred this issue fromon Apr 10, 2022
  12. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Nov 27, 2023
  13. serhiy-storchaka commented on Aug 3, 2026

    @serhiy-storchaka
    Member

    gh-155097 (PR #155099) adds a formatter parameter to csv.writer, passed through by DictWriter. It replaces the str() call, and is called only for values that are neither strings nor None — i.e. exactly the values a strict mode would need to check:

    def strict(index, value):
        if not hasattr(type(value), '__index__') and not hasattr(type(value), '__float__'):
            raise TypeError(f'column {index}: {type(value).__name__} is not a number or a string')
        return str(value)

    That is the nb_index/nb_float check discussed above: Decimal, Fraction and NumPy numbers pass, Path and UUID do not, and bytes is rejected rather than triggering BytesWarning.

    A dedicated strict=True would still be more discoverable than a four-line hook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.10 (EOL)end of lifestdlibStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancement

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions