-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
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
Make Calendar.itermonthdates() behave consistently in edge cases #72479
Comments
The Calendar.itermonthdates() method is defined as follows: "Return an iterator for one month. The iterator will yield datetime.date values and will always iterate through complete weeks, so it will yield dates outside the specified month." However, for the two months at the extremes of datetime.date range, 0001-01 and 9999-12, the dates outside the specified month may not be representable as datetime.date instances. The current implementation is inconsistent: itermonthdates(1, 1) may raise an OverflowError (see bpo-26650), while itermonthdates(9999, 12) may yield an incomplete week (see bpo-28253.) |
Possible solutions (in any case the documentation needs changes):
Examples of the usage of itermonthdates(): https://github.com/sunlightlabs/django-locksmith/blob/master/locksmith/hub/dataviews.py |
I would like to take the #1 approach, and also implement an itermonthdays3() generator that would be like itermonthdates(), but return 3-tuples (year, month, day) instead of datetime.date objects. The name "itermonthdays3" is subject to discussion, but it fits with the existing "itermonthdays" and "itermonthdays2" that yield integers and 2-tuples respectively. An alternative, but slightly longer name would be "itermonthdatetuples". itermonthdates() can then be reimplemented as def itermonthdates(self, year, month):
for y, m, d in self.itermonthdays3(year, month):
yield datetime.date(y, m, d) with the obvious out of bounds behavior. |
LGTM. Maybe add also itermonthdays4() that yields 4-tuples (year, month, day, day_of_week)? I seen a code that filters out weekends from itermonthdates(). |
Do you mind to create a pull request Alexander? |
Let me look into this. It's been a while ... |
I submitted PR 4079. Serhiy, please review the logic and if this matches what we discussed a year ago, I will add the docs and NEWS entries. |
Please mark all the non-public helper functions as being private by using a leading underscore for their names. The __all__ listing is correct but is insufficient. Note, the module already used the leading underscore convention for the some of the non-public helper classes. Already, we have a user confused by this: https://twitter.com/andreportela85/status/1148956749652738049 |
There are two ways to indicate that a function is not public: either make its name underscored, or add __all__ and do not include the function name in it. The purpose of __all__ is to avoid mass renaming of internal functions whis is a code churn and reduces readability. If make all internal names underscored, __all__ would be not needed. |
For people using "import calendar", the __all__ variable has no effect. Running help(calendar) shows the functions as if they were public functions. The module historically hid its private details with the leading underscores. The patch in question violated that norm. We have evidence that a real user was confused by this. Please fix it. |
s/help/dir/ |
There are hundreds or thousands of private names in other modules. Do you propose to change them all? I afraid that this will cause more harm than benefit. |
No. But we have precedent in this module and should maintain it. FWIW, there are a number of modules that have been conscientious in this regard (for example, collections and random). |
In general, applying different rules to standard library modules and changing private function naming conventions on a case-by-case basis creates rather drastic inconsistency. There definitely should be a universal standard across stdlib, especially for something as fundamental as private function naming. The precedent really should not be on a per-module basis. As someone who joined the Python development community only a month ago but was a user of the language for 5 years, the most common convention to denote privation functions was a preceding underscore. In a perfect world where simplicity is the only concern, this should be the guideline in which stdlib follow consistently across the modules. However, Serhiy makes a very valid point:
__all__ has been far easier to maintain since functions can be added or removed without issue and there's no need to rename them. However, as far as I am aware, this is no clear documentation that membership on the __all__ list denotes whether or not a function is public. Also, any user using "import module" instead of "from module import *" may not be aware they are accessing a private function. Here's a few solutions I thought of (not mutually exclusive):
The exact convention for marking functions as public or private is not nearly as important as having universal consistency across stdlib and clear communication to the users. This does not seem to be the case at the moment. |
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:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: