• Argument name should be lowercase

    From dn@21:1/5 to All on Fri Nov 11 21:54:26 2022
    PyCharm is warning against using an identifier of all upper-case letters
    as a function's parameter, saying "Argument name should be lowercase".
    (weak, code smell)


    The application consists of three+ files:
    - configuration
    - mainline script
    - module of workbook functions

    The mainline reads the configuration parameters to set the application's environment. All of the config/settings are constants. Some of them
    appear as a dictionary (PRICES_WORKBOOK) defining a workbook's
    (spreadsheet's) parameters, eg the filename, which work-sheet to use, etc.


    The mainline calls the relevant functions from within the module,
    as-needed:-

    import prices_workbook as pw
    ...
    product_prices = pw.build_product_prices_dictionary( PRICES_WORKBOOK )


    The module's function definition is:

    def build_product_prices_dictionary( WORKBOOK_DEFINITIONS:dict )->dict:
    ...
    price_array = xl.iget_array(
    file_name=WORKBOOK_DEFINITIONS[ "file_name" ],
    ...

    (the function def is flagged, as above)


    A quick scan of PEP-008 failed to yield anything relevant. Why is this
    frowned upon as poor Python, or a matter of style?

    Yes, a dict is mutable, but the upper-case denoting a constant indicates
    that none of its values are to be changed by the programmer.

    As far as the function is concerned, the dict and its contents are
    constants.
    (but the dict can't be treated as a global ENV[IRONMENT] object, because
    it has to cross into the module's namespace)


    Is passing the dict as an argument/parameter considered to be
    incompatible with its designation as a constant?

    Perhaps the style should be more enum-like, ie the dict's name in
    lower-case, with the key-named in upper case, eg

    workbook_definitions[ "FILE_NAME" ]


    Am not particularly concerned by the IDE raising this as a 'problem' -
    will quite happily ignore and carry-on; but am curious as to the logic
    behind the analysis - and why it doesn't come readily to mind.

    Advice, comments, critique welcome!

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Gerard" on Fri Nov 11 12:03:31 2022
    "Weatherby,Gerard" <[email protected]> writes:
    I'd personally find it weird to see an all-cap parameter

    In the source code of the standard library, all-caps
    notation is used for a parameter name sometimes
    if that parameter name is "URL" or sometimes
    when it is being initialized from an all-caps name as in:

    |def __del__(self, _warn=warnings.warn, RUN=RUN):
    | if self._state == RUN:
    ...
    from "pool.py".

    ("RUN=RUN" makes RUN have the value "RUN" had
    at the time of the definition of the function.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Weatherby,Gerard@21:1/5 to All on Fri Nov 11 11:28:53 2022
    PEP 8 doesn�t explicitly list a naming convention for function parameters, but every example shows them as lowercase, even though the function doesn�t modify them.

    See also the Python tutorial ( https://docs.python.org/3/tutorial/controlflow.html#defining-functions ), which also shows all parameters as lowercase.

    I�d personally find it weird to see an all-cap parameter (Why are you yelling?). I expect ALL_CAPS to be hardcoded values.



    From: Python-list <python-list-bounces+gweatherby=[email protected]> on behalf of dn <[email protected]>
    Date: Friday, November 11, 2022 at 3:56 AM
    To: 'Python' <[email protected]>
    Subject: Argument name should be lowercase
    *** Attention: This is an external email. Use caution responding, opening attachments or clicking on links. ***

    PyCharm is warning against using an identifier of all upper-case letters
    as a function's parameter, saying "Argument name should be lowercase".
    (weak, code smell)


    The application consists of three+ files:
    - configuration
    - mainline script
    - module of workbook functions

    The mainline reads the configuration parameters to set the application's environment. All of the config/settings are constants. Some of them
    appear as a dictionary (PRICES_WORKBOOK) defining a workbook's
    (spreadsheet's) parameters, eg the filename, which work-sheet to use, etc.


    The mainline calls the relevant functions from within the module,
    as-needed:-

    import prices_workbook as pw
    ...
    product_prices = pw.build_product_prices_dictionary( PRICES_WORKBOOK )


    The module's function definition is:

    def build_product_prices_dictionary( WORKBOOK_DEFINITIONS:dict )->dict:
    ...
    price_array = xl.iget_array(
    file_name=WORKBOOK_DEFINITIONS[ "file_name" ],
    ...

    (the function def is flagged, as above)


    A quick scan of PEP-008 failed to yield anything relevant. Why is this
    frowned upon as poor Python, or a matter of style?

    Yes, a dict is mutable, but the upper-case denoting a constant indicates
    that none of its values are to be changed by the programmer.

    As far as the function is concerned, the dict and its contents are
    constants.
    (but the dict can't be treated as a global ENV[IRONMENT] object, because
    it has to cross into the module's namespace)


    Is passing the dict as an argument/parameter considered to be
    incompatible with its designation as a constant?

    Perhaps the style should be more enum-like, ie the dict's name in
    lower-case, with the key-named in upper case, eg

    workbook_definitions[ "FILE_NAME" ]


    Am not particularly concerned by the IDE raising this as a 'problem' -
    will quite happily ignore and carry-on; but am curious as to the logic
    behind the analysis - and why it doesn't come readily to mind.

    Advice, comments, critique welcome!

    --
    Regards,
    =dn
    -- https://urldefense.com/v3/__https://mail.python.org/mailman/listinfo/python-list__;!!Cn_UX_p3!h56Cia7ERYDmxaCnEo0k9hfXz-mTJrz43UqHjbfhwLjutjhQE1QU975lUXTBf38la5kXAkBHdzyzOY4XAObbAPOa-ebC-HNY$<https://urldefense.com/v3/__https:/mail.python.org/mailman/
    listinfo/python-list__;!!Cn_UX_p3!h56Cia7ERYDmxaCnEo0k9hfXz-mTJrz43UqHjbfhwLjutjhQE1QU975lUXTBf38la5kXAkBHdzyzOY4XAObbAPOa-ebC-HNY$>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to All on Fri Nov 11 09:09:51 2022
    This is a matter of convention. Historically, many language
    practitioners got used to using all-caps for key constants. This makes
    it easier to tell when you are using (or misusing) one, for one thing.

    For myself, I also will use all-caps for quasi-constants, ones that are
    set only once, for example from command-line parameters.

    In your example,I would not use all-caps for the formal parameter in the function definition. I would have written

    def build_product_prices_dictionary(workbook_definitions:dict )->dict:
    ...
    price_array = xl.iget_array(
    file_name=workbook_definitions[ "file_name" ],

    There is no value in making a formal parameter's name be all-caps, since
    even if it were the same string as an actual global parameter, it would
    not mean that actual parameter: it is only a placeholder. There could
    even be a negative consequence, because later you might forget and think
    that the formal parameter's name meant that the global parameter would
    be used automatically in the function call, as if it were a default
    parameter. At a minimum, this could lead to confusion about your
    intent, at a maximum it could end up being a bug.

    Perhaps you wrote it that way as a reminder which dict to use. If so,
    that kind of information would better go into the docstring:

    def build_product_prices_dictionary(workbook_definitions:dict) -> dict:
    """Return a dictionary of product prices given their definitions.

    ARGUMENT
    workbook_definitions -- a dict of product definitions, typically
    the global WORKBOOK_DEFINITIONS.
    """
    # ...

    Alternatively, you could make the global be the default for the argument:

    def build_product_prices_dictionary(workbook_definitions:dict =
    WORKBOOK_DEFINITIONS)->dict:

    This might or might not make sense depending on how you plan to use the function.

    So basically, PyCharm is suggesting that you use a clearer, less
    problem-prone style of naming. I'd heed the advice. It would also be
    in line with what many other programmers are used to reading, and that's
    a positive advantage.

    On 11/11/2022 3:54 AM, dn wrote:
    PyCharm is warning against using an identifier of all upper-case letters
    as a function's parameter, saying "Argument name should be lowercase".
    (weak, code smell)


    The application consists of three+ files:
    - configuration
    - mainline script
    - module of workbook functions

    The mainline reads the configuration parameters to set the application's environment. All of the config/settings are constants. Some of them
    appear as a dictionary (PRICES_WORKBOOK) defining a workbook's (spreadsheet's) parameters, eg the filename, which work-sheet to use, etc.


    The mainline calls the relevant functions from within the module,
    as-needed:-

    import prices_workbook as pw
    ...
    product_prices = pw.build_product_prices_dictionary( PRICES_WORKBOOK )


    The module's function definition is:

    def build_product_prices_dictionary( WORKBOOK_DEFINITIONS:dict )->dict:
    ...
        price_array = xl.iget_array(
            file_name=WORKBOOK_DEFINITIONS[ "file_name" ],
            ...

    (the function def is flagged, as above)


    A quick scan of PEP-008 failed to yield anything relevant. Why is this frowned upon as poor Python, or a matter of style?

    Yes, a dict is mutable, but the upper-case denoting a constant indicates
    that none of its values are to be changed by the programmer.

    As far as the function is concerned, the dict and its contents are
    constants.
    (but the dict can't be treated as a global ENV[IRONMENT] object, because
    it has to cross into the module's namespace)


    Is passing the dict as an argument/parameter considered to be
    incompatible with its designation as a constant?

    Perhaps the style should be more enum-like, ie the dict's name in
    lower-case, with the key-named in upper case, eg

        workbook_definitions[ "FILE_NAME" ]


    Am not particularly concerned by the IDE raising this as a 'problem' -
    will quite happily ignore and carry-on; but am curious as to the logic
    behind the analysis - and why it doesn't come readily to mind.

    Advice, comments, critique welcome!


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From MRAB@21:1/5 to All on Fri Nov 11 15:03:32 2022
    On 2022-11-11 08:54, dn wrote:
    [snip]

    The module's function definition is:

    def build_product_prices_dictionary( WORKBOOK_DEFINITIONS:dict )->dict:
    ...
    price_array = xl.iget_array(
    file_name=WORKBOOK_DEFINITIONS[ "file_name" ],
    ...

    (the function def is flagged, as above)


    A quick scan of PEP-008 failed to yield anything relevant. Why is this frowned upon as poor Python, or a matter of style?

    Yes, a dict is mutable, but the upper-case denoting a constant indicates
    that none of its values are to be changed by the programmer.

    As far as the function is concerned, the dict and its contents are
    constants.
    (but the dict can't be treated as a global ENV[IRONMENT] object, because
    it has to cross into the module's namespace)

    [snip]
    I think the problem is that the dict _is_ mutable, so it's not a
    constant; it's read-only, which is not the same thing.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to MRAB on Fri Nov 11 15:30:52 2022
    MRAB <[email protected]> writes:
    [snip]
    I think the problem is that the dict _is_ mutable, so it's not a
    constant; it's read-only, which is not the same thing.

    In Python, the literals and some names (like "Ellipsis") are
    called "constant(s)".

    |The Ellipsis built-in constant.
    from the Glossary of the Python Language Reference

    "Ellipsis" wouldn't be a "constant" by the terms as used in
    Java, because in Pyton one can execute

    Ellipsis = 1

    , and then "Ellipsis" will be 1, even

    import builtins
    builtins.Ellipsis
    |Ellipsis
    builtins.Ellipsis = 1
    builtins.Ellipsis
    |1

    . In Java, "const" means that one cannot assign to the /name/
    (while the object can still change). So, when "dict" is a
    const name in Java, one cannot do "dict = ...",
    but "dict.change()" is still allowed in Java.

    In C++, "const" means that one cannot change the /object/.
    So, when "dict" is const, in C++, "dict.change()" is not allowed
    (Notwithstanding so called "mutable" fields). One also cannot
    change objects through a "pointer to const", while one could
    change objects through a "const pointer" (but not the pointer
    itself).

    (Above, ".change" is supposed to be a method that changes its
    object.)

    In Python, there is no such definition for the meaning of
    "const" as "const" is not part of the language. So, Java
    programmers comming to Python might have other ideas of
    "const" than C++ programmers.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Weatherby,Gerard@21:1/5 to All on Fri Nov 11 16:25:22 2022
    If you wanted to document/enforce the input argument is immutable, you could do one of the following. You�d get a type warning in PyCharm with bad_func or equivalent, and bad_func2 will fail at runtime.

    def bad_func(x: typing.Mapping):
    """Get type warning if x modified"""
    x[3] = 7


    def bad_func2(x: types.MappingProxyType):
    """Get runtime error if x modified"""
    if not isinstance(x, types.MappingProxyType):
    x = types.MappingProxyType(x)
    x[3] = 8


    From: Python-list <python-list-bounces+gweatherby=[email protected]> on behalf of dn <[email protected]>
    Date: Friday, November 11, 2022 at 3:56 AM
    To: 'Python' <[email protected]>
    Subject: Argument name should be lowercase
    *** Attention: This is an external email. Use caution responding, opening attachments or clicking on links. ***

    PyCharm is warning against using an identifier of all upper-case letters
    as a function's parameter, saying "Argument name should be lowercase".
    (weak, code smell)


    The application consists of three+ files:
    - configuration
    - mainline script
    - module of workbook functions

    The mainline reads the configuration parameters to set the application's environment. All of the config/settings are constants. Some of them
    appear as a dictionary (PRICES_WORKBOOK) defining a workbook's
    (spreadsheet's) parameters, eg the filename, which work-sheet to use, etc.


    The mainline calls the relevant functions from within the module,
    as-needed:-

    import prices_workbook as pw
    ...
    product_prices = pw.build_product_prices_dictionary( PRICES_WORKBOOK )


    The module's function definition is:

    def build_product_prices_dictionary( WORKBOOK_DEFINITIONS:dict )->dict:
    ...
    price_array = xl.iget_array(
    file_name=WORKBOOK_DEFINITIONS[ "file_name" ],
    ...

    (the function def is flagged, as above)


    A quick scan of PEP-008 failed to yield anything relevant. Why is this
    frowned upon as poor Python, or a matter of style?

    Yes, a dict is mutable, but the upper-case denoting a constant indicates
    that none of its values are to be changed by the programmer.

    As far as the function is concerned, the dict and its contents are
    constants.
    (but the dict can't be treated as a global ENV[IRONMENT] object, because
    it has to cross into the module's namespace)


    Is passing the dict as an argument/parameter considered to be
    incompatible with its designation as a constant?

    Perhaps the style should be more enum-like, ie the dict's name in
    lower-case, with the key-named in upper case, eg

    workbook_definitions[ "FILE_NAME" ]


    Am not particularly concerned by the IDE raising this as a 'problem' -
    will quite happily ignore and carry-on; but am curious as to the logic
    behind the analysis - and why it doesn't come readily to mind.

    Advice, comments, critique welcome!

    --
    Regards,
    =dn
    -- https://urldefense.com/v3/__https://mail.python.org/mailman/listinfo/python-list__;!!Cn_UX_p3!h56Cia7ERYDmxaCnEo0k9hfXz-mTJrz43UqHjbfhwLjutjhQE1QU975lUXTBf38la5kXAkBHdzyzOY4XAObbAPOa-ebC-HNY$<https://urldefense.com/v3/__https:/mail.python.org/mailman/
    listinfo/python-list__;!!Cn_UX_p3!h56Cia7ERYDmxaCnEo0k9hfXz-mTJrz43UqHjbfhwLjutjhQE1QU975lUXTBf38la5kXAkBHdzyzOY4XAObbAPOa-ebC-HNY$>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Stefan Ram on Sat Nov 12 07:20:58 2022
    On Sat, 12 Nov 2022 at 06:42, Stefan Ram <[email protected]> wrote:

    "Weatherby,Gerard" <[email protected]> writes:
    I'd personally find it weird to see an all-cap parameter

    In the source code of the standard library, all-caps
    notation is used for a parameter name sometimes
    if that parameter name is "URL" or sometimes
    when it is being initialized from an all-caps name as in:

    |def __del__(self, _warn=warnings.warn, RUN=RUN):
    | if self._state == RUN:
    ...
    from "pool.py".

    ("RUN=RUN" makes RUN have the value "RUN" had
    at the time of the definition of the function.)


    There are a few reasons to do that "snapshot" trick. The most common
    is performance, but in this case, my guess is that (since it's a
    __del__ method) it's to ensure that the objects are still referenced
    when this function is called - to stop them getting disposed of
    prematurely. Very rare, but important occasionally.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Probably 'nuff on Sat Nov 12 11:07:31 2022
    Thanks for the thoughts!


    On 11/11/2022 21.54, dn wrote:
    PyCharm is warning against using an identifier of all upper-case letters
    as a function's parameter, saying "Argument name should be lowercase".
    (weak, code smell)

    ...
    PEP-008: makes no mention, and is but a guide anyway.
    (that said, if one 'breaks a rule', then a good reason should be required!)

    YELLING is an email-interpretation. Does it apply to code? Particularly
    as we are talking Python, where an identifier using all upper-case
    letters is a convention (not a language-structure, as stated in
    contributions 'here') that is widely used.

    Accordingly, the purpose of the UPPER_CASE is to communicate the
    read-only nature of the data-item to the programmer. Combine this with
    "we're all adults here", and if someone is foolish-enough to modify a 'constant', then Python will comply - but (s)he can expect push-back
    during a Code Review! So, yes, «weird to see an all-cap parameter» (I
    thought so too) but isn't that effect the purpose of the convention in
    the first place?

    There are several aspects of Python where the 'we're all adults'
    thinking must be applied, eg 'private attributes'. Given that
    understanding, it doesn't seem necessary to force constant-behavior on
    the parameter - although when one does, there are a couple of mechanisms
    and more than several projects working on this and other aspects of
    enforcing data-types and their characteristics!

    That said, and with @Stefan's observations, there are many reasons why
    this code is piling-up trouble - and thus, should be avoided...


    def build_product_prices_dictionary( WORKBOOK_DEFINITIONS:dict )->dict:
    ...
        price_array = xl.iget_array(
            file_name=WORKBOOK_DEFINITIONS[ "file_name" ],
            ...

    (the function def is flagged, as above)

    As far as the function is concerned, the dict and its contents are
    constants.
    (but the dict can't be treated as a global ENV[IRONMENT] object, because
    it has to cross into the module's namespace)

    By way of background, in recent times, have the habit/standardised code 'template' for config/environment-setting, which instantiates a class
    from (at least) JSON/YAML files. Accordingly, the instance is named in lower-case, and particular groups of parameters (as here) can be passed
    as an extract-function/property (as a general style, I avoid long parameter/argument lists, preferring a data-collection - which landed me
    in this...).

    Which re-raises the question the other way around: how does the object's
    name indicate its constant/read-only nature to the reader?
    "Ouch" says idealism!

    Back to this case, which part of a tutorial comparing different methods
    to access prices in a product-catalog[ue] (eg hard-coded dict,
    flat-file, workbook, database, etc). Some members of the group are
    either anti-OOP or OOP-untrained. Hence avoiding my personal 'good, old, stand-by'.

    (plus it was Veterans'/Remembrance/Liberation Day, which we don't
    observe (much) here (ANZAC Day instead) and I was using some
    creative-coding time to [try to] take my mind off it)

    The particular @Rob and I both find it peculiar (in the same sense) but as-above, that's (ultimately) the point of the upper-casing.

    The idea of moving the workbook-definitions into that module appears to
    make sense and could easily be achieved - but in the singular context of
    this example. However, as a matter of style, all of an application's environment-setting would best be done in one place - with cmdLN, config-file(s), etc, all being combined, and with the output of a single 'authority' as its objective.

    I could try to 'get away with it', but if some Apprentice takes the idea
    and later uses it as a 'template', a general grumpiness will result...
    (no it's not a learning-objective, but sometimes people take-away
    unintended 'side effects', maybe like this).

    However, in that spirit, am contemplating use of a DataClass. It will be
    as easy to read as any config file, even to non-OOP-ers; has no learning side-effect down-side (that I've spotted, as-yet); and can be 'seen' as
    a instance by the workbook module (instance named using lower-case).
    This, hopefully also measuring-up to @Thomas' observations of risk that
    the current code's intentions be misconstrued later.

    I'll admit to (idealists look away now!) not being 'above' the use of
    globals, particularly?if only an ENVIRONMENT class - IIRC this
    irresponsible behavior being when the environment is fairly trivial (cf multi-layered or large numbers of 'tunable factors').

    Because the ENVIRONMENT is returned to the mainline, which subsequently
    uses those parameters to call the 'action' functions/methods (and know
    which to call), it is not available within the import-ed module's
    namespace. Hence the fall-back to passing it/the Workbook sub-set of parameters, as an argument. (see above for normal/traditional 'solution'
    to traversing namespaces)


    Is passing the dict as an argument/parameter considered to be
    incompatible with its designation as a constant?

    There's an argument to be made, particularly by those from other
    languages, relating to pass-by-reference, pass-by-value; which suggests
    that the WORKBOOK_DEFINITIONS parameter is effectively being used on the
    LHS of an assignment...

    Probably 'nuff said'!


    Perhaps the style should be more enum-like, ie the dict's name in
    lower-case, with the key-named in upper case, eg

        workbook_definitions[ "FILE_NAME" ]

    Like @MRAB, I'm thinking that getting tangled-up in the conventions of
    constant identification, cf wanting to convey the read-only nature of
    the construct is unhelpful (and an unneeded headache from over-thinking).

    Changing the dict-keys to upper-case encourages the 'constant/read-only' interpretation, and might cause least distraction to the learning/discussion/comparison objectives...


    Advice, comments, critique welcome!

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Weatherby,Gerard@21:1/5 to Gerard" on Sat Nov 12 14:40:56 2022
    RUN is a global constant, and the method is documented, explaining why the parameter is there:

    # Copy globals as function locals to make sure that they are available
    # during Python shutdown when the Pool is destroyed.
    def __del__(self, _warn=warnings.warn, RUN=RUN):

    From: Python-list <python-list-bounces+gweatherby=[email protected]> on behalf of Stefan Ram <[email protected]>
    Date: Friday, November 11, 2022 at 2:42 PM
    To: [email protected] <[email protected]>
    Subject: Re: Argument name should be lowercase
    *** Attention: This is an external email. Use caution responding, opening attachments or clicking on links. ***

    "Weatherby,Gerard" <[email protected]> writes:
    I'd personally find it weird to see an all-cap parameter

    In the source code of the standard library, all-caps
    notation is used for a parameter name sometimes
    if that parameter name is "URL" or sometimes
    when it is being initialized from an all-caps name as in:

    |def __del__(self, _warn=warnings.warn, RUN=RUN):
    | if self._state == RUN:
    ...
    from "pool.py".

    ("RUN=RUN" makes RUN have the value "RUN" had
    at the time of the definition of the function.)


    -- https://urldefense.com/v3/__https://mail.python.org/mailman/listinfo/python-list__;!!Cn_UX_p3!kI1c1EIpXCtnz0SBHvQmJokWXPBo0rCY9MQ-IwXOZU4RyHqqKho9wMu6Ekj6GMXA0EbReT8_4GOxvoldiOsL3W8$<https://urldefense.com/v3/__https:/mail.python.org/mailman/listinfo/
    python-list__;!!Cn_UX_p3!kI1c1EIpXCtnz0SBHvQmJokWXPBo0rCY9MQ-IwXOZU4RyHqqKho9wMu6Ekj6GMXA0EbReT8_4GOxvoldiOsL3W8$>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)