hyperflask 0.4.4__tar.gz → 0.5.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 (122) hide show
  1. {hyperflask-0.4.4 → hyperflask-0.5.0}/PKG-INFO +3 -2
  2. {hyperflask-0.4.4 → hyperflask-0.5.0}/pyproject.toml +3 -2
  3. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/app.py +12 -3
  4. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/components/jsx.py +2 -2
  5. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/components/webcomponent.py +2 -2
  6. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/layouts/web.html +1 -1
  7. hyperflask-0.5.0/src/hyperflask/utils/image.py +26 -0
  8. {hyperflask-0.4.4 → hyperflask-0.5.0}/README.md +0 -0
  9. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/__init__.py +0 -0
  10. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/__main__.py +0 -0
  11. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/actors.py +0 -0
  12. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/cli/__init__.py +0 -0
  13. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/cli/reloader.py +0 -0
  14. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/cli/runner.py +0 -0
  15. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/cli/worker.py +0 -0
  16. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/components/__init__.py +0 -0
  17. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/components/alpine.py +0 -0
  18. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/components/core.py +0 -0
  19. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/factory.py +0 -0
  20. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/forms/__init__.py +0 -0
  21. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/forms/fields.py +0 -0
  22. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/forms/widgets.py +0 -0
  23. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/layouts/email.mjml +0 -0
  24. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/model.py +0 -0
  25. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/page_helpers.py +0 -0
  26. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/security.py +0 -0
  27. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/static/alpine-csp.js +0 -0
  28. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/static/alpine.js +0 -0
  29. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/static/app.css +0 -0
  30. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/static/app.js +0 -0
  31. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/static/htmx-exts.js +0 -0
  32. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/static/react.js +0 -0
  33. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/static/stimulus.js +0 -0
  34. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/static/translations.js +0 -0
  35. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Accordion.html +0 -0
  36. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/AccordionPanel.html +0 -0
  37. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Alert.html +0 -0
  38. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Avatar.html +0 -0
  39. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/AvatarGroup.html +0 -0
  40. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Badge.html +0 -0
  41. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Breadcrumbs.html +0 -0
  42. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/BreadcrumbsItem.html +0 -0
  43. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Button.html +0 -0
  44. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Card.html +0 -0
  45. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/CardActions.html +0 -0
  46. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/CardTitle.html +0 -0
  47. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/ChatBubble.html +0 -0
  48. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Checkbox.html +0 -0
  49. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/CollapsibleSubMenu.html +0 -0
  50. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Countdown.html +0 -0
  51. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Divider.html +0 -0
  52. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Drawer.html +0 -0
  53. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/DrawerContent.html +0 -0
  54. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/DrawerSide.html +0 -0
  55. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Dropdown.html +0 -0
  56. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/DropdownItem.html +0 -0
  57. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Fieldset.html +0 -0
  58. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FieldsetLegend.html +0 -0
  59. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FileInput.html +0 -0
  60. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Filter.html +0 -0
  61. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FilterItem.html +0 -0
  62. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Footer.html +0 -0
  63. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FooterLink.html +0 -0
  64. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FooterNav.html +0 -0
  65. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Indicator.html +0 -0
  66. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Input.html +0 -0
  67. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/InputLabel.html +0 -0
  68. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Join.html +0 -0
  69. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Kbd.html +0 -0
  70. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Label.html +0 -0
  71. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/LabeledCheckbox.html +0 -0
  72. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/LabeledToggle.html +0 -0
  73. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Link.html +0 -0
  74. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/List.html +0 -0
  75. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/ListItem.html +0 -0
  76. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Loading.html +0 -0
  77. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Menu.html +0 -0
  78. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/MenuItem.html +0 -0
  79. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/MenuTitle.html +0 -0
  80. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Modal.html +0 -0
  81. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/ModalAction.html +0 -0
  82. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/ModalTitle.html +0 -0
  83. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Navbar.html +0 -0
  84. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Pagination.html +0 -0
  85. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/PaginationNext.html +0 -0
  86. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/PaginationPage.html +0 -0
  87. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/PaginationPrev.html +0 -0
  88. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Progress.html +0 -0
  89. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/README.md +0 -0
  90. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Radio.html +0 -0
  91. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Range.html +0 -0
  92. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Rating.html +0 -0
  93. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Select.html +0 -0
  94. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Stack.html +0 -0
  95. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Stat.html +0 -0
  96. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Stats.html +0 -0
  97. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Step.html +0 -0
  98. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Steps.html +0 -0
  99. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/SubMenu.html +0 -0
  100. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Swap.html +0 -0
  101. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Tab.html +0 -0
  102. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Table.html +0 -0
  103. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Tabs.html +0 -0
  104. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Textarea.html +0 -0
  105. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Toast.html +0 -0
  106. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Toggle.html +0 -0
  107. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Tooltip.html +0 -0
  108. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/flash.html +0 -0
  109. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/forms.html +0 -0
  110. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/icons.html +0 -0
  111. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/layout.html +0 -0
  112. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/modal.html +0 -0
  113. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/skeleton.html +0 -0
  114. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/ui/sse.html +0 -0
  115. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/utils/__init__.py +0 -0
  116. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/utils/freezer.py +0 -0
  117. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/utils/html.py +0 -0
  118. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/utils/htmx.py +0 -0
  119. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/utils/markdown.py +0 -0
  120. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/utils/metadata.py +0 -0
  121. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/utils/page_actions.py +0 -0
  122. {hyperflask-0.4.4 → hyperflask-0.5.0}/src/hyperflask/utils/tokens.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperflask
3
- Version: 0.4.4
3
+ Version: 0.5.0
4
4
  Summary: Full stack web framework
5
5
  Author: Maxime Bouroumeau-Fuseau
6
6
  Author-email: Maxime Bouroumeau-Fuseau <maxime.bouroumeau@gmail.com>
7
7
  License-Expression: MIT
8
8
  Requires-Dist: flask>=3.0.0,<4.0.0
9
- Requires-Dist: flask-assets-pipeline~=0.7
9
+ Requires-Dist: flask-assets-pipeline~=0.8
10
10
  Requires-Dist: flask-babel-hyper~=5.1
11
11
  Requires-Dist: flask-collections~=0.3
12
12
  Requires-Dist: flask-configurator~=0.1
@@ -32,6 +32,7 @@ Requires-Dist: jinja-wtforms~=0.2
32
32
  Requires-Dist: periodiq~=0.13
33
33
  Requires-Dist: python-slugify~=8.0.4
34
34
  Requires-Dist: watchdog>=6.0.0
35
+ Requires-Dist: pillow>=11.3.0
35
36
  Requires-Python: >=3.10
36
37
  Project-URL: Repository, https://github.com/hyperflask/hyperflask
37
38
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyperflask"
3
- version = "0.4.4"
3
+ version = "0.5.0"
4
4
  description = "Full stack web framework"
5
5
  authors = [
6
6
  {"name" = "Maxime Bouroumeau-Fuseau", email = "maxime.bouroumeau@gmail.com"}
@@ -10,7 +10,7 @@ license = "MIT"
10
10
  requires-python = ">=3.10"
11
11
  dependencies = [
12
12
  "flask>=3.0.0,<4.0.0",
13
- "flask-assets-pipeline ~=0.7",
13
+ "flask-assets-pipeline ~=0.8",
14
14
  "flask-babel-hyper ~=5.1",
15
15
  "flask-collections ~=0.3",
16
16
  "flask-configurator ~=0.1",
@@ -37,6 +37,7 @@ dependencies = [
37
37
  "periodiq ~=0.13",
38
38
  "python-slugify ~=8.0.4",
39
39
  "watchdog>=6.0.0",
40
+ "pillow>=11.3.0",
40
41
  ]
41
42
 
42
43
  [tool.uv.sources]
@@ -31,6 +31,7 @@ from .utils.markdown import jinja_markdown, MarkdownExtension
31
31
  from .utils.html import sanitize_html, nl2br
32
32
  from .utils.metadata import metadata_tags
33
33
  from .utils.freezer import StaticMode, Freezer, freezer_url_generator
34
+ from .utils.image import image_tag
34
35
  from .components import register_components
35
36
  from .model import Model, File as SQLFileType, UndefinedDatabase
36
37
  from .actors import AppContextMiddleware, discover_broker, make_actor_decorator
@@ -95,7 +96,9 @@ class Hyperflask(Flask):
95
96
  "CSP_FRAME_ANCESTORS": True,
96
97
  "CSP_FRAME_ANCESTORS_SAFE_ENDPOINTS": [],
97
98
  "REFERRER_POLICY": "strict-origin-when-cross-origin",
98
- "HSTS_HEADER": False
99
+ "HSTS_HEADER": False,
100
+ "IMAGES_DEFAULT_LOADING": "lazy",
101
+ "IMAGES_DEFAULT_DECODING": "async",
99
102
  })
100
103
  if config:
101
104
  self.config.update(config)
@@ -126,8 +129,13 @@ class Hyperflask(Flask):
126
129
  self.jinja_env.add_extension(LayoutExtension)
127
130
  self.jinja_env.add_extension(WtformExtension)
128
131
  self.jinja_env.add_extension(MarkdownExtension)
129
- self.jinja_env.filters.update(markdown=jinja_markdown, sanitize=sanitize_html, nl2br=nl2br)
130
- self.jinja_env.globals.update(page_action_url=page_action_url, app=self, csp_nonce=csp_nonce, metadata_tags=metadata_tags)
132
+ self.jinja_env.filters.update(markdown=jinja_markdown,
133
+ sanitize=sanitize_html,
134
+ nl2br=nl2br)
135
+ self.jinja_env.globals.update(page_action_url=page_action_url,
136
+ app=self,
137
+ csp_nonce=csp_nonce,
138
+ metadata_tags=metadata_tags)
131
139
  self.jinja_env.form_base_cls = Form
132
140
  self.jinja_env.default_layout = self.config["LAYOUT"]
133
141
  self.forms = self.jinja_env.forms
@@ -197,6 +205,7 @@ class Hyperflask(Flask):
197
205
  if hasattr(file_routes, "loader"):
198
206
  self.forms.register_from_loader(file_routes.loader, "pages")
199
207
  self.macros.create_from_func(htmx_oob, "HtmxOob", receive_caller=True, caller_alias="html")
208
+ self.macros.create_from_func(image_tag, "Image")
200
209
 
201
210
  self.components_loader, _ = register_components(self)
202
211
  if self.components_loader:
@@ -1,7 +1,7 @@
1
1
  from .core import BaseComponentAdapter
2
2
  from markupsafe import Markup
3
3
  from flask import current_app
4
- from flask_assets_pipeline import Entrypoint
4
+ from flask_assets_pipeline import BundleEntrypoint
5
5
  import json
6
6
  import html
7
7
 
@@ -13,7 +13,7 @@ class JsxComponentAdapter(BaseComponentAdapter):
13
13
  app.assets.state.bundles["@components"] = []
14
14
  app.assets.include("@components")
15
15
  app.assets.state.bundles["@components"].append(
16
- Entrypoint.create(self.template, from_package="jinja"))
16
+ BundleEntrypoint.create(self.template, from_package="jinja"))
17
17
  app.assets.include(self.include_js)
18
18
 
19
19
  def render(self, caller, *args, **kwargs):
@@ -1,6 +1,6 @@
1
1
  from .core import BaseComponentAdapter
2
2
  from jinja_super_macros import html_tag
3
- from flask_assets_pipeline import Entrypoint
3
+ from flask_assets_pipeline import BundleEntrypoint
4
4
  from markupsafe import Markup
5
5
  import os
6
6
 
@@ -17,7 +17,7 @@ class WebComponentAdapter(BaseComponentAdapter):
17
17
  app.assets.state.bundles["@components"] = []
18
18
  app.assets.include("@components")
19
19
  app.assets.state.bundles["@components"].append(
20
- Entrypoint.create(os.path.abspath(tpl.filename), self.template))
20
+ BundleEntrypoint.create(os.path.abspath(tpl.filename), self.template))
21
21
 
22
22
  def render(self, caller, *args, **kwargs):
23
23
  tag_name = self.name.replace("_", "-")
@@ -5,7 +5,7 @@
5
5
  {% block head_metas %}
6
6
  {{ metadata_tags(page.get('metadata', {})) }}
7
7
  {% endblock %}
8
- {% asset_tags nonce=csp_nonce %}
8
+ {% asset_tags(nonce=csp_nonce) %}
9
9
  {% block head_assets %}{% endblock %}
10
10
  {%- endblock %}
11
11
  </head>
@@ -0,0 +1,26 @@
1
+ from flask import current_app
2
+ from jinja_super_macros import html_tag
3
+ from flask_assets_pipeline import image_attrs
4
+
5
+
6
+ def image_tag(src, priority=False, preload=False, placeholder=True, loading=None, decoding=None, **attrs):
7
+ if not loading:
8
+ loading = current_app.config["IMAGES_DEFAULT_LOADING"]
9
+ if not decoding:
10
+ decoding = current_app.config["IMAGES_DEFAULT_DECODING"]
11
+ if priority:
12
+ preload = True
13
+ attrs.setdefault("fetchpriority", "high")
14
+ if preload:
15
+ current_app.assets.include([(src, {"modifier": "preload", "content_type": "image"})])
16
+ if loading == "lazy":
17
+ loading = "eager"
18
+ _attrs = image_attrs(src)
19
+ if not placeholder and "style" in _attrs:
20
+ del _attrs["style"]
21
+ if loading:
22
+ _attrs["loading"] = loading
23
+ if decoding:
24
+ _attrs["decoding"] = decoding
25
+ _attrs.update(attrs)
26
+ return html_tag("img", **_attrs)
File without changes