plain 0.14.1__tar.gz → 0.16.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. {plain-0.14.1 → plain-0.16.0}/PKG-INFO +1 -1
  2. {plain-0.14.1 → plain-0.16.0}/plain/internal/middleware/headers.py +6 -0
  3. {plain-0.14.1 → plain-0.16.0}/plain/utils/timesince.py +79 -42
  4. {plain-0.14.1 → plain-0.16.0}/pyproject.toml +1 -1
  5. {plain-0.14.1 → plain-0.16.0}/uv.lock +2 -2
  6. {plain-0.14.1 → plain-0.16.0}/.gitignore +0 -0
  7. {plain-0.14.1 → plain-0.16.0}/LICENSE +0 -0
  8. {plain-0.14.1 → plain-0.16.0}/README.md +0 -0
  9. {plain-0.14.1 → plain-0.16.0}/plain/README.md +0 -0
  10. {plain-0.14.1 → plain-0.16.0}/plain/__main__.py +0 -0
  11. {plain-0.14.1 → plain-0.16.0}/plain/assets/README.md +0 -0
  12. {plain-0.14.1 → plain-0.16.0}/plain/assets/__init__.py +0 -0
  13. {plain-0.14.1 → plain-0.16.0}/plain/assets/compile.py +0 -0
  14. {plain-0.14.1 → plain-0.16.0}/plain/assets/finders.py +0 -0
  15. {plain-0.14.1 → plain-0.16.0}/plain/assets/fingerprints.py +0 -0
  16. {plain-0.14.1 → plain-0.16.0}/plain/assets/urls.py +0 -0
  17. {plain-0.14.1 → plain-0.16.0}/plain/assets/views.py +0 -0
  18. {plain-0.14.1 → plain-0.16.0}/plain/cli/README.md +0 -0
  19. {plain-0.14.1 → plain-0.16.0}/plain/cli/__init__.py +0 -0
  20. {plain-0.14.1 → plain-0.16.0}/plain/cli/cli.py +0 -0
  21. {plain-0.14.1 → plain-0.16.0}/plain/cli/formatting.py +0 -0
  22. {plain-0.14.1 → plain-0.16.0}/plain/cli/packages.py +0 -0
  23. {plain-0.14.1 → plain-0.16.0}/plain/cli/print.py +0 -0
  24. {plain-0.14.1 → plain-0.16.0}/plain/cli/startup.py +0 -0
  25. {plain-0.14.1 → plain-0.16.0}/plain/csrf/README.md +0 -0
  26. {plain-0.14.1 → plain-0.16.0}/plain/csrf/middleware.py +0 -0
  27. {plain-0.14.1 → plain-0.16.0}/plain/csrf/views.py +0 -0
  28. {plain-0.14.1 → plain-0.16.0}/plain/debug.py +0 -0
  29. {plain-0.14.1 → plain-0.16.0}/plain/exceptions.py +0 -0
  30. {plain-0.14.1 → plain-0.16.0}/plain/forms/README.md +0 -0
  31. {plain-0.14.1 → plain-0.16.0}/plain/forms/__init__.py +0 -0
  32. {plain-0.14.1 → plain-0.16.0}/plain/forms/boundfield.py +0 -0
  33. {plain-0.14.1 → plain-0.16.0}/plain/forms/exceptions.py +0 -0
  34. {plain-0.14.1 → plain-0.16.0}/plain/forms/fields.py +0 -0
  35. {plain-0.14.1 → plain-0.16.0}/plain/forms/forms.py +0 -0
  36. {plain-0.14.1 → plain-0.16.0}/plain/http/README.md +0 -0
  37. {plain-0.14.1 → plain-0.16.0}/plain/http/__init__.py +0 -0
  38. {plain-0.14.1 → plain-0.16.0}/plain/http/cookie.py +0 -0
  39. {plain-0.14.1 → plain-0.16.0}/plain/http/multipartparser.py +0 -0
  40. {plain-0.14.1 → plain-0.16.0}/plain/http/request.py +0 -0
  41. {plain-0.14.1 → plain-0.16.0}/plain/http/response.py +0 -0
  42. {plain-0.14.1 → plain-0.16.0}/plain/internal/__init__.py +0 -0
  43. {plain-0.14.1 → plain-0.16.0}/plain/internal/files/README.md +0 -0
  44. {plain-0.14.1 → plain-0.16.0}/plain/internal/files/__init__.py +0 -0
  45. {plain-0.14.1 → plain-0.16.0}/plain/internal/files/base.py +0 -0
  46. {plain-0.14.1 → plain-0.16.0}/plain/internal/files/locks.py +0 -0
  47. {plain-0.14.1 → plain-0.16.0}/plain/internal/files/move.py +0 -0
  48. {plain-0.14.1 → plain-0.16.0}/plain/internal/files/temp.py +0 -0
  49. {plain-0.14.1 → plain-0.16.0}/plain/internal/files/uploadedfile.py +0 -0
  50. {plain-0.14.1 → plain-0.16.0}/plain/internal/files/uploadhandler.py +0 -0
  51. {plain-0.14.1 → plain-0.16.0}/plain/internal/files/utils.py +0 -0
  52. {plain-0.14.1 → plain-0.16.0}/plain/internal/handlers/__init__.py +0 -0
  53. {plain-0.14.1 → plain-0.16.0}/plain/internal/handlers/base.py +0 -0
  54. {plain-0.14.1 → plain-0.16.0}/plain/internal/handlers/exception.py +0 -0
  55. {plain-0.14.1 → plain-0.16.0}/plain/internal/handlers/wsgi.py +0 -0
  56. {plain-0.14.1 → plain-0.16.0}/plain/internal/middleware/__init__.py +0 -0
  57. {plain-0.14.1 → plain-0.16.0}/plain/internal/middleware/https.py +0 -0
  58. {plain-0.14.1 → plain-0.16.0}/plain/internal/middleware/slash.py +0 -0
  59. {plain-0.14.1 → plain-0.16.0}/plain/json.py +0 -0
  60. {plain-0.14.1 → plain-0.16.0}/plain/logs/README.md +0 -0
  61. {plain-0.14.1 → plain-0.16.0}/plain/logs/__init__.py +0 -0
  62. {plain-0.14.1 → plain-0.16.0}/plain/logs/configure.py +0 -0
  63. {plain-0.14.1 → plain-0.16.0}/plain/logs/loggers.py +0 -0
  64. {plain-0.14.1 → plain-0.16.0}/plain/logs/utils.py +0 -0
  65. {plain-0.14.1 → plain-0.16.0}/plain/packages/README.md +0 -0
  66. {plain-0.14.1 → plain-0.16.0}/plain/packages/__init__.py +0 -0
  67. {plain-0.14.1 → plain-0.16.0}/plain/packages/config.py +0 -0
  68. {plain-0.14.1 → plain-0.16.0}/plain/packages/registry.py +0 -0
  69. {plain-0.14.1 → plain-0.16.0}/plain/paginator.py +0 -0
  70. {plain-0.14.1 → plain-0.16.0}/plain/preflight/README.md +0 -0
  71. {plain-0.14.1 → plain-0.16.0}/plain/preflight/__init__.py +0 -0
  72. {plain-0.14.1 → plain-0.16.0}/plain/preflight/files.py +0 -0
  73. {plain-0.14.1 → plain-0.16.0}/plain/preflight/messages.py +0 -0
  74. {plain-0.14.1 → plain-0.16.0}/plain/preflight/registry.py +0 -0
  75. {plain-0.14.1 → plain-0.16.0}/plain/preflight/security.py +0 -0
  76. {plain-0.14.1 → plain-0.16.0}/plain/preflight/urls.py +0 -0
  77. {plain-0.14.1 → plain-0.16.0}/plain/runtime/README.md +0 -0
  78. {plain-0.14.1 → plain-0.16.0}/plain/runtime/__init__.py +0 -0
  79. {plain-0.14.1 → plain-0.16.0}/plain/runtime/global_settings.py +0 -0
  80. {plain-0.14.1 → plain-0.16.0}/plain/runtime/user_settings.py +0 -0
  81. {plain-0.14.1 → plain-0.16.0}/plain/signals/README.md +0 -0
  82. {plain-0.14.1 → plain-0.16.0}/plain/signals/__init__.py +0 -0
  83. {plain-0.14.1 → plain-0.16.0}/plain/signals/dispatch/__init__.py +0 -0
  84. {plain-0.14.1 → plain-0.16.0}/plain/signals/dispatch/dispatcher.py +0 -0
  85. {plain-0.14.1 → plain-0.16.0}/plain/signals/dispatch/license.txt +0 -0
  86. {plain-0.14.1 → plain-0.16.0}/plain/signing.py +0 -0
  87. {plain-0.14.1 → plain-0.16.0}/plain/templates/README.md +0 -0
  88. {plain-0.14.1 → plain-0.16.0}/plain/templates/__init__.py +0 -0
  89. {plain-0.14.1 → plain-0.16.0}/plain/templates/core.py +0 -0
  90. {plain-0.14.1 → plain-0.16.0}/plain/templates/jinja/README.md +0 -0
  91. {plain-0.14.1 → plain-0.16.0}/plain/templates/jinja/__init__.py +0 -0
  92. {plain-0.14.1 → plain-0.16.0}/plain/templates/jinja/environments.py +0 -0
  93. {plain-0.14.1 → plain-0.16.0}/plain/templates/jinja/extensions.py +0 -0
  94. {plain-0.14.1 → plain-0.16.0}/plain/templates/jinja/filters.py +0 -0
  95. {plain-0.14.1 → plain-0.16.0}/plain/templates/jinja/globals.py +0 -0
  96. {plain-0.14.1 → plain-0.16.0}/plain/test/README.md +0 -0
  97. {plain-0.14.1 → plain-0.16.0}/plain/test/__init__.py +0 -0
  98. {plain-0.14.1 → plain-0.16.0}/plain/test/client.py +0 -0
  99. {plain-0.14.1 → plain-0.16.0}/plain/urls/README.md +0 -0
  100. {plain-0.14.1 → plain-0.16.0}/plain/urls/__init__.py +0 -0
  101. {plain-0.14.1 → plain-0.16.0}/plain/urls/base.py +0 -0
  102. {plain-0.14.1 → plain-0.16.0}/plain/urls/conf.py +0 -0
  103. {plain-0.14.1 → plain-0.16.0}/plain/urls/converters.py +0 -0
  104. {plain-0.14.1 → plain-0.16.0}/plain/urls/exceptions.py +0 -0
  105. {plain-0.14.1 → plain-0.16.0}/plain/urls/resolvers.py +0 -0
  106. {plain-0.14.1 → plain-0.16.0}/plain/utils/README.md +0 -0
  107. {plain-0.14.1 → plain-0.16.0}/plain/utils/__init__.py +0 -0
  108. {plain-0.14.1 → plain-0.16.0}/plain/utils/_os.py +0 -0
  109. {plain-0.14.1 → plain-0.16.0}/plain/utils/cache.py +0 -0
  110. {plain-0.14.1 → plain-0.16.0}/plain/utils/connection.py +0 -0
  111. {plain-0.14.1 → plain-0.16.0}/plain/utils/crypto.py +0 -0
  112. {plain-0.14.1 → plain-0.16.0}/plain/utils/datastructures.py +0 -0
  113. {plain-0.14.1 → plain-0.16.0}/plain/utils/dateformat.py +0 -0
  114. {plain-0.14.1 → plain-0.16.0}/plain/utils/dateparse.py +0 -0
  115. {plain-0.14.1 → plain-0.16.0}/plain/utils/dates.py +0 -0
  116. {plain-0.14.1 → plain-0.16.0}/plain/utils/deconstruct.py +0 -0
  117. {plain-0.14.1 → plain-0.16.0}/plain/utils/decorators.py +0 -0
  118. {plain-0.14.1 → plain-0.16.0}/plain/utils/deprecation.py +0 -0
  119. {plain-0.14.1 → plain-0.16.0}/plain/utils/duration.py +0 -0
  120. {plain-0.14.1 → plain-0.16.0}/plain/utils/email.py +0 -0
  121. {plain-0.14.1 → plain-0.16.0}/plain/utils/encoding.py +0 -0
  122. {plain-0.14.1 → plain-0.16.0}/plain/utils/functional.py +0 -0
  123. {plain-0.14.1 → plain-0.16.0}/plain/utils/hashable.py +0 -0
  124. {plain-0.14.1 → plain-0.16.0}/plain/utils/html.py +0 -0
  125. {plain-0.14.1 → plain-0.16.0}/plain/utils/http.py +0 -0
  126. {plain-0.14.1 → plain-0.16.0}/plain/utils/inspect.py +0 -0
  127. {plain-0.14.1 → plain-0.16.0}/plain/utils/ipv6.py +0 -0
  128. {plain-0.14.1 → plain-0.16.0}/plain/utils/itercompat.py +0 -0
  129. {plain-0.14.1 → plain-0.16.0}/plain/utils/module_loading.py +0 -0
  130. {plain-0.14.1 → plain-0.16.0}/plain/utils/regex_helper.py +0 -0
  131. {plain-0.14.1 → plain-0.16.0}/plain/utils/safestring.py +0 -0
  132. {plain-0.14.1 → plain-0.16.0}/plain/utils/text.py +0 -0
  133. {plain-0.14.1 → plain-0.16.0}/plain/utils/timezone.py +0 -0
  134. {plain-0.14.1 → plain-0.16.0}/plain/utils/tree.py +0 -0
  135. {plain-0.14.1 → plain-0.16.0}/plain/validators.py +0 -0
  136. {plain-0.14.1 → plain-0.16.0}/plain/views/README.md +0 -0
  137. {plain-0.14.1 → plain-0.16.0}/plain/views/__init__.py +0 -0
  138. {plain-0.14.1 → plain-0.16.0}/plain/views/base.py +0 -0
  139. {plain-0.14.1 → plain-0.16.0}/plain/views/csrf.py +0 -0
  140. {plain-0.14.1 → plain-0.16.0}/plain/views/errors.py +0 -0
  141. {plain-0.14.1 → plain-0.16.0}/plain/views/exceptions.py +0 -0
  142. {plain-0.14.1 → plain-0.16.0}/plain/views/forms.py +0 -0
  143. {plain-0.14.1 → plain-0.16.0}/plain/views/objects.py +0 -0
  144. {plain-0.14.1 → plain-0.16.0}/plain/views/redirect.py +0 -0
  145. {plain-0.14.1 → plain-0.16.0}/plain/views/templates.py +0 -0
  146. {plain-0.14.1 → plain-0.16.0}/plain/wsgi.py +0 -0
  147. {plain-0.14.1 → plain-0.16.0}/tests/.bolt/assets_collected/assets.json +0 -0
  148. {plain-0.14.1 → plain-0.16.0}/tests/.gitignore +0 -0
  149. {plain-0.14.1 → plain-0.16.0}/tests/app/.gitignore +0 -0
  150. {plain-0.14.1 → plain-0.16.0}/tests/app/settings.py +0 -0
  151. {plain-0.14.1 → plain-0.16.0}/tests/app/test/__init__.py +0 -0
  152. {plain-0.14.1 → plain-0.16.0}/tests/app/test/default_settings.py +0 -0
  153. {plain-0.14.1 → plain-0.16.0}/tests/app/urls.py +0 -0
  154. {plain-0.14.1 → plain-0.16.0}/tests/conftest.py +0 -0
  155. {plain-0.14.1 → plain-0.16.0}/tests/test_cli.py +0 -0
  156. {plain-0.14.1 → plain-0.16.0}/tests/test_runtime.py +0 -0
  157. {plain-0.14.1 → plain-0.16.0}/tests/test_wsgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain
3
- Version: 0.14.1
3
+ Version: 0.16.0
4
4
  Summary: A web framework for building products with Python.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-File: LICENSE
@@ -9,6 +9,12 @@ class DefaultHeadersMiddleware:
9
9
  response = self.get_response(request)
10
10
 
11
11
  for header, value in settings.DEFAULT_RESPONSE_HEADERS.items():
12
+ # Since we don't have a good way to *remote* default response headers,
13
+ # use allow users to set them to an empty string to indicate they should be removed.
14
+ if header in response.headers and response.headers[header] == "":
15
+ del response.headers[header]
16
+ continue
17
+
12
18
  response.headers.setdefault(header, value)
13
19
 
14
20
  # Add the Content-Length header to non-streaming responses if not
@@ -4,59 +4,93 @@ from plain.utils.html import avoid_wrapping
4
4
  from plain.utils.text import pluralize_lazy
5
5
  from plain.utils.timezone import is_aware
6
6
 
7
- TIME_STRINGS = {
8
- "year": pluralize_lazy("%(num)d year", "%(num)d years", "num"),
9
- "month": pluralize_lazy("%(num)d month", "%(num)d months", "num"),
10
- "week": pluralize_lazy("%(num)d week", "%(num)d weeks", "num"),
11
- "day": pluralize_lazy("%(num)d day", "%(num)d days", "num"),
12
- "hour": pluralize_lazy("%(num)d hour", "%(num)d hours", "num"),
13
- "minute": pluralize_lazy("%(num)d minute", "%(num)d minutes", "num"),
14
- }
15
7
 
16
- TIME_STRINGS_KEYS = list(TIME_STRINGS.keys())
17
-
18
- TIME_CHUNKS = [
19
- 60 * 60 * 24 * 7, # week
20
- 60 * 60 * 24, # day
21
- 60 * 60, # hour
22
- 60, # minute
23
- ]
24
-
25
- MONTHS_DAYS = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
26
-
27
-
28
- def timesince(d, now=None, reversed=False, time_strings=None, depth=2):
8
+ def timesince(
9
+ d: datetime.datetime,
10
+ *,
11
+ now: datetime.datetime | None = None,
12
+ reversed: bool = False,
13
+ format: str | dict[str, str] = "verbose",
14
+ depth: int = 2,
15
+ ) -> str:
29
16
  """
30
17
  Take two datetime objects and return the time between d and now as a nicely
31
- formatted string, e.g. "10 minutes". If d occurs after now, return
32
- "0 minutes".
18
+ formatted string, e.g., "10 minutes" or "10m" (depending on the format).
19
+
20
+ `format` can be:
21
+ - "verbose": e.g., "1 year, 2 months"
22
+ - "short": e.g., "1y 2m"
23
+ - A custom dictionary defining time unit formats.
33
24
 
34
25
  Units used are years, months, weeks, days, hours, and minutes.
35
26
  Seconds and microseconds are ignored.
36
27
 
37
28
  The algorithm takes into account the varying duration of years and months.
38
- There is exactly "1 year, 1 month" between 2013/02/10 and 2014/03/10,
39
- but also between 2007/08/10 and 2008/09/10 despite the delta being 393 days
40
- in the former case and 397 in the latter.
29
+ For example, there is exactly "1 year, 1 month" between 2013/02/10 and
30
+ 2014/03/10, but also between 2007/08/10 and 2008/09/10 despite the delta
31
+ being 393 days in the former case and 397 in the latter.
41
32
 
42
- Up to `depth` adjacent units will be displayed. For example,
33
+ Up to `depth` adjacent units will be displayed. For example,
43
34
  "2 weeks, 3 days" and "1 year, 3 months" are possible outputs, but
44
35
  "2 weeks, 3 hours" and "1 year, 5 days" are not.
45
36
 
46
- `time_strings` is an optional dict of strings to replace the default
47
- TIME_STRINGS dict.
48
-
49
- `depth` is an optional integer to control the number of adjacent time
50
- units returned.
51
-
52
- Originally adapted from
53
- https://web.archive.org/web/20060617175230/http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
54
- Modified to improve results for years and months.
37
+ Arguments:
38
+ d: A datetime object representing the starting time.
39
+ now: A datetime object representing the current time. Defaults to the
40
+ current time if not provided.
41
+ reversed: If True, calculates time until `d` rather than since `d`.
42
+ format: The output format, either "verbose", "short", or a custom
43
+ dictionary of time unit formats.
44
+ depth: An integer specifying the number of adjacent time units to display.
45
+
46
+ Returns:
47
+ A string representing the time difference, formatted according to the
48
+ specified format.
49
+
50
+ Raises:
51
+ ValueError: If depth is less than 1 or if format is invalid.
55
52
  """
56
- if time_strings is None:
57
- time_strings = TIME_STRINGS
53
+ TIME_CHUNKS = [
54
+ 60 * 60 * 24 * 7, # week
55
+ 60 * 60 * 24, # day
56
+ 60 * 60, # hour
57
+ 60, # minute
58
+ ]
59
+ MONTHS_DAYS = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
60
+ TIME_STRINGS_KEYS = ["year", "month", "week", "day", "hour", "minute"]
61
+
62
+ VERBOSE_TIME_STRINGS = {
63
+ "year": pluralize_lazy("%(num)d year", "%(num)d years", "num"),
64
+ "month": pluralize_lazy("%(num)d month", "%(num)d months", "num"),
65
+ "week": pluralize_lazy("%(num)d week", "%(num)d weeks", "num"),
66
+ "day": pluralize_lazy("%(num)d day", "%(num)d days", "num"),
67
+ "hour": pluralize_lazy("%(num)d hour", "%(num)d hours", "num"),
68
+ "minute": pluralize_lazy("%(num)d minute", "%(num)d minutes", "num"),
69
+ }
70
+ SHORT_TIME_STRINGS = {
71
+ "year": "%(num)dy",
72
+ "month": "%(num)dmo",
73
+ "week": "%(num)dw",
74
+ "day": "%(num)dd",
75
+ "hour": "%(num)dh",
76
+ "minute": "%(num)dm",
77
+ }
78
+
79
+ # Determine time_strings based on format
80
+ if format == "verbose":
81
+ time_strings = VERBOSE_TIME_STRINGS
82
+ elif format == "short":
83
+ time_strings = SHORT_TIME_STRINGS
84
+ elif isinstance(format, dict):
85
+ time_strings = format
86
+ else:
87
+ raise ValueError(
88
+ "format must be 'verbose', 'short', or a custom dictionary of formats."
89
+ )
90
+
58
91
  if depth <= 0:
59
92
  raise ValueError("depth must be greater than 0.")
93
+
60
94
  # Convert datetime.date to datetime.datetime for comparison.
61
95
  if not isinstance(d, datetime.datetime):
62
96
  d = datetime.datetime(d.year, d.month, d.day)
@@ -82,8 +116,6 @@ def timesince(d, now=None, reversed=False, time_strings=None, depth=2):
82
116
  years, months = divmod(total_months, 12)
83
117
 
84
118
  # Calculate the remaining time.
85
- # Create a "pivot" datetime shifted from d by years and months, then use
86
- # that to determine the other parts.
87
119
  if years or months:
88
120
  pivot_year = d.year + years
89
121
  pivot_month = d.month + months
@@ -131,8 +163,13 @@ def timesince(d, now=None, reversed=False, time_strings=None, depth=2):
131
163
  return ", ".join(result)
132
164
 
133
165
 
134
- def timeuntil(d, now=None, time_strings=None, depth=2):
166
+ def timeuntil(
167
+ d: datetime.datetime,
168
+ now: datetime.datetime | None = None,
169
+ format: str | dict[str, str] = "verbose",
170
+ depth: int = 2,
171
+ ) -> str:
135
172
  """
136
173
  Like timesince, but return a string measuring the time until the given time.
137
174
  """
138
- return timesince(d, now, reversed=True, time_strings=time_strings, depth=depth)
175
+ return timesince(d, now=now, reversed=True, format=format, depth=depth)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "plain"
3
- version = "0.14.1"
3
+ version = "0.16.0"
4
4
  description = "A web framework for building products with Python."
5
5
  authors = [{name = "Dave Gaeddert", email = "dave.gaeddert@dropseed.dev"}]
6
6
  readme = "README.md"
@@ -6,7 +6,7 @@ name = "click"
6
6
  version = "8.1.8"
7
7
  source = { registry = "https://pypi.org/simple" }
8
8
  dependencies = [
9
- { name = "colorama", marker = "platform_system == 'Windows'" },
9
+ { name = "colorama", marker = "sys_platform == 'win32'" },
10
10
  ]
11
11
  sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
12
12
  wheels = [
@@ -102,7 +102,7 @@ wheels = [
102
102
 
103
103
  [[package]]
104
104
  name = "plain"
105
- version = "0.14.1"
105
+ version = "0.16.0"
106
106
  source = { editable = "." }
107
107
  dependencies = [
108
108
  { name = "click" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes