restiny 0.2.1__py3-none-any.whl → 0.6.1__py3-none-any.whl
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.
- restiny/__about__.py +1 -1
- restiny/__main__.py +28 -14
- restiny/assets/style.tcss +56 -2
- restiny/consts.py +236 -0
- restiny/data/db.py +60 -0
- restiny/data/models.py +111 -0
- restiny/data/repos.py +455 -0
- restiny/data/sql/__init__.py +3 -0
- restiny/entities.py +438 -0
- restiny/enums.py +14 -5
- restiny/httpx_auths.py +52 -0
- restiny/ui/__init__.py +17 -0
- restiny/ui/app.py +586 -0
- restiny/ui/collections_area.py +594 -0
- restiny/ui/environments_screen.py +270 -0
- restiny/ui/request_area.py +602 -0
- restiny/{core → ui}/response_area.py +4 -1
- restiny/ui/settings_screen.py +73 -0
- restiny/ui/top_bar_area.py +60 -0
- restiny/{core → ui}/url_area.py +54 -38
- restiny/utils.py +52 -15
- restiny/widgets/__init__.py +15 -1
- restiny/widgets/collections_tree.py +74 -0
- restiny/widgets/confirm_prompt.py +76 -0
- restiny/widgets/custom_input.py +20 -0
- restiny/widgets/dynamic_fields.py +65 -70
- restiny/widgets/password_input.py +161 -0
- restiny/widgets/path_chooser.py +12 -12
- {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/METADATA +7 -5
- restiny-0.6.1.dist-info/RECORD +38 -0
- restiny/core/__init__.py +0 -15
- restiny/core/app.py +0 -348
- restiny/core/request_area.py +0 -337
- restiny-0.2.1.dist-info/RECORD +0 -24
- {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/WHEEL +0 -0
- {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/entry_points.txt +0 -0
- {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {restiny-0.2.1.dist-info → restiny-0.6.1.dist-info}/top_level.txt +0 -0
|
@@ -10,12 +10,12 @@ from textual.widget import Widget
|
|
|
10
10
|
from textual.widgets import (
|
|
11
11
|
Button,
|
|
12
12
|
ContentSwitcher,
|
|
13
|
-
Input,
|
|
14
13
|
RadioButton,
|
|
15
14
|
RadioSet,
|
|
16
15
|
Switch,
|
|
17
16
|
)
|
|
18
17
|
|
|
18
|
+
from restiny.widgets import CustomInput
|
|
19
19
|
from restiny.widgets.path_chooser import PathChooser
|
|
20
20
|
|
|
21
21
|
|
|
@@ -142,24 +142,24 @@ class TextDynamicField(DynamicField):
|
|
|
142
142
|
self, enabled: bool, key: str, value: str, *args, **kwargs
|
|
143
143
|
) -> None:
|
|
144
144
|
super().__init__(*args, **kwargs)
|
|
145
|
-
self.
|
|
146
|
-
self.
|
|
147
|
-
self.
|
|
145
|
+
self._enabled = enabled
|
|
146
|
+
self._key = key
|
|
147
|
+
self._value = value
|
|
148
148
|
|
|
149
149
|
def compose(self) -> ComposeResult:
|
|
150
150
|
yield Switch(
|
|
151
|
-
value=self.
|
|
151
|
+
value=self._enabled,
|
|
152
152
|
tooltip='Send this field?',
|
|
153
153
|
id='enabled',
|
|
154
154
|
)
|
|
155
|
-
yield
|
|
156
|
-
value=self.
|
|
155
|
+
yield CustomInput(
|
|
156
|
+
value=self._key,
|
|
157
157
|
placeholder='Key',
|
|
158
158
|
select_on_focus=False,
|
|
159
159
|
id='key',
|
|
160
160
|
)
|
|
161
|
-
yield
|
|
162
|
-
value=self.
|
|
161
|
+
yield CustomInput(
|
|
162
|
+
value=self._value,
|
|
163
163
|
placeholder='Value',
|
|
164
164
|
select_on_focus=False,
|
|
165
165
|
id='value',
|
|
@@ -168,8 +168,8 @@ class TextDynamicField(DynamicField):
|
|
|
168
168
|
|
|
169
169
|
async def on_mount(self) -> None:
|
|
170
170
|
self.enabled_switch = self.query_one('#enabled', Switch)
|
|
171
|
-
self.key_input = self.query_one('#key',
|
|
172
|
-
self.value_input = self.query_one('#value',
|
|
171
|
+
self.key_input = self.query_one('#key', CustomInput)
|
|
172
|
+
self.value_input = self.query_one('#value', CustomInput)
|
|
173
173
|
self.remove_button = self.query_one('#remove', Button)
|
|
174
174
|
|
|
175
175
|
@property
|
|
@@ -211,9 +211,9 @@ class TextDynamicField(DynamicField):
|
|
|
211
211
|
elif message.value is False:
|
|
212
212
|
self.post_message(message=self.Disabled(field=self))
|
|
213
213
|
|
|
214
|
-
@on(
|
|
215
|
-
@on(
|
|
216
|
-
def on_input_changed(self, message:
|
|
214
|
+
@on(CustomInput.Changed, '#key')
|
|
215
|
+
@on(CustomInput.Changed, '#value')
|
|
216
|
+
def on_input_changed(self, message: CustomInput.Changed) -> None:
|
|
217
217
|
self.enabled_switch.value = True
|
|
218
218
|
|
|
219
219
|
if self.is_empty:
|
|
@@ -260,51 +260,51 @@ class TextOrFileDynamicField(DynamicField):
|
|
|
260
260
|
**kwargs,
|
|
261
261
|
) -> None:
|
|
262
262
|
super().__init__(*args, **kwargs)
|
|
263
|
-
self.
|
|
264
|
-
self.
|
|
265
|
-
self.
|
|
266
|
-
self.
|
|
263
|
+
self._enabled = enabled
|
|
264
|
+
self._key = key
|
|
265
|
+
self._value = value
|
|
266
|
+
self._value_kind = value_kind
|
|
267
267
|
|
|
268
268
|
def compose(self) -> ComposeResult:
|
|
269
269
|
with RadioSet(id='value-kind', compact=True):
|
|
270
270
|
yield RadioButton(
|
|
271
271
|
label=_ValueKind.TEXT,
|
|
272
|
-
value=bool(self.
|
|
272
|
+
value=bool(self._value_kind == _ValueKind.TEXT),
|
|
273
273
|
id='value-kind-text',
|
|
274
274
|
)
|
|
275
275
|
yield RadioButton(
|
|
276
276
|
label=_ValueKind.FILE,
|
|
277
|
-
value=bool(self.
|
|
277
|
+
value=bool(self._value_kind == _ValueKind.FILE),
|
|
278
278
|
id='value-kind-file',
|
|
279
279
|
)
|
|
280
280
|
yield Switch(
|
|
281
|
-
value=self.
|
|
281
|
+
value=self._enabled,
|
|
282
282
|
tooltip='Send this field?',
|
|
283
283
|
id='enabled',
|
|
284
284
|
)
|
|
285
|
-
yield
|
|
286
|
-
value=self.
|
|
285
|
+
yield CustomInput(
|
|
286
|
+
value=self._key,
|
|
287
287
|
placeholder='Key',
|
|
288
288
|
select_on_focus=False,
|
|
289
289
|
id='key',
|
|
290
290
|
)
|
|
291
291
|
with ContentSwitcher(
|
|
292
292
|
initial='value-text'
|
|
293
|
-
if self.
|
|
293
|
+
if self._value_kind == _ValueKind.TEXT
|
|
294
294
|
else 'value-file',
|
|
295
295
|
id='value-kind-switcher',
|
|
296
296
|
):
|
|
297
|
-
yield
|
|
298
|
-
value=self.
|
|
299
|
-
if self.
|
|
297
|
+
yield CustomInput(
|
|
298
|
+
value=self._value
|
|
299
|
+
if self._value_kind == _ValueKind.TEXT
|
|
300
300
|
else '',
|
|
301
301
|
placeholder='Value',
|
|
302
302
|
select_on_focus=False,
|
|
303
303
|
id='value-text',
|
|
304
304
|
)
|
|
305
305
|
yield PathChooser.file(
|
|
306
|
-
path=self.
|
|
307
|
-
if self.
|
|
306
|
+
path=self._value
|
|
307
|
+
if self._value_kind == _ValueKind.FILE
|
|
308
308
|
else None,
|
|
309
309
|
id='value-file',
|
|
310
310
|
)
|
|
@@ -323,8 +323,8 @@ class TextOrFileDynamicField(DynamicField):
|
|
|
323
323
|
'#value-kind-file', RadioButton
|
|
324
324
|
)
|
|
325
325
|
self.enabled_switch = self.query_one('#enabled', Switch)
|
|
326
|
-
self.key_input = self.query_one('#key',
|
|
327
|
-
self.value_text_input = self.query_one('#value-text',
|
|
326
|
+
self.key_input = self.query_one('#key', CustomInput)
|
|
327
|
+
self.value_text_input = self.query_one('#value-text', CustomInput)
|
|
328
328
|
self.value_file_input = self.query_one('#value-file', PathChooser)
|
|
329
329
|
self.remove_button = self.query_one('#remove', Button)
|
|
330
330
|
|
|
@@ -403,11 +403,11 @@ class TextOrFileDynamicField(DynamicField):
|
|
|
403
403
|
elif message.value is False:
|
|
404
404
|
self.post_message(message=self.Disabled(field=self))
|
|
405
405
|
|
|
406
|
-
@on(
|
|
407
|
-
@on(
|
|
406
|
+
@on(CustomInput.Changed, '#key')
|
|
407
|
+
@on(CustomInput.Changed, '#value-text')
|
|
408
408
|
@on(PathChooser.Changed, '#value-file')
|
|
409
409
|
def on_input_changed(
|
|
410
|
-
self, message:
|
|
410
|
+
self, message: CustomInput.Changed | PathChooser.Changed
|
|
411
411
|
) -> None:
|
|
412
412
|
self.enabled_switch.value = True
|
|
413
413
|
|
|
@@ -493,27 +493,41 @@ class DynamicFields(Widget):
|
|
|
493
493
|
def filled_fields(self) -> list[DynamicField]:
|
|
494
494
|
return [field for field in self.fields if field.is_filled]
|
|
495
495
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
496
|
+
async def add_field(
|
|
497
|
+
self, field: DynamicField, before_last: bool = False
|
|
498
|
+
) -> None:
|
|
499
|
+
if before_last:
|
|
500
|
+
await self.fields_container.mount(field, before=self.fields[-1])
|
|
501
|
+
else:
|
|
502
|
+
await self.fields_container.mount(field)
|
|
503
|
+
|
|
504
|
+
def remove_field(
|
|
505
|
+
self, field: DynamicField, focus_neighbor: bool = False
|
|
506
|
+
) -> None:
|
|
507
|
+
if len(self.fields) == 1:
|
|
508
|
+
self.app.bell()
|
|
509
|
+
return
|
|
510
|
+
elif field is self.fields[-1]:
|
|
511
|
+
self.app.bell()
|
|
512
|
+
return
|
|
513
|
+
|
|
514
|
+
if focus_neighbor:
|
|
515
|
+
field_index = self.fields.index(field)
|
|
516
|
+
|
|
517
|
+
neighbor_field = None
|
|
518
|
+
if field_index == 0:
|
|
519
|
+
neighbor_field = self.fields[field_index + 1]
|
|
520
|
+
else:
|
|
521
|
+
neighbor_field = self.fields[field_index - 1]
|
|
522
|
+
|
|
523
|
+
self.app.set_focus(neighbor_field.query_one(CustomInput))
|
|
524
|
+
|
|
511
525
|
field.add_class('hidden')
|
|
512
526
|
field.remove()
|
|
513
527
|
|
|
514
528
|
@on(DynamicField.Empty)
|
|
515
529
|
def _on_field_is_empty(self, message: DynamicField.Empty) -> None:
|
|
516
|
-
self.
|
|
530
|
+
self.remove_field(field=message.field, focus_neighbor=True)
|
|
517
531
|
self.post_message(
|
|
518
532
|
message=self.FieldEmpty(fields=self, field=message.field)
|
|
519
533
|
)
|
|
@@ -544,23 +558,4 @@ class DynamicFields(Widget):
|
|
|
544
558
|
def _on_field_remove_requested(
|
|
545
559
|
self, message: DynamicField.RemoveRequested
|
|
546
560
|
) -> None:
|
|
547
|
-
self.
|
|
548
|
-
|
|
549
|
-
def _focus_neighbor_field_then_remove(self, field: DynamicField) -> None:
|
|
550
|
-
if len(self.fields) == 1:
|
|
551
|
-
self.app.bell()
|
|
552
|
-
return
|
|
553
|
-
elif field is self.fields[-1]:
|
|
554
|
-
self.app.bell()
|
|
555
|
-
return
|
|
556
|
-
|
|
557
|
-
field_index = self.fields.index(field)
|
|
558
|
-
|
|
559
|
-
neighbor_field = None
|
|
560
|
-
if field_index == 0:
|
|
561
|
-
neighbor_field = self.fields[field_index + 1]
|
|
562
|
-
else:
|
|
563
|
-
neighbor_field = self.fields[field_index - 1]
|
|
564
|
-
|
|
565
|
-
self.app.set_focus(neighbor_field.query_one(Input))
|
|
566
|
-
self.remove_field(field=field)
|
|
561
|
+
self.remove_field(field=message.field, focus_neighbor=True)
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
3
|
+
from textual import on
|
|
4
|
+
from textual.app import ComposeResult
|
|
5
|
+
from textual.containers import Horizontal
|
|
6
|
+
from textual.message import Message
|
|
7
|
+
from textual.widget import Widget
|
|
8
|
+
from textual.widgets import Button
|
|
9
|
+
|
|
10
|
+
from restiny.widgets import CustomInput
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class _Icon(StrEnum):
|
|
14
|
+
SHOW = ' 🔓 '
|
|
15
|
+
HIDE = ' 🔒 '
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _Tooltip(StrEnum):
|
|
19
|
+
SHOW = 'Show'
|
|
20
|
+
HIDE = 'Hide'
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PasswordInput(Widget):
|
|
24
|
+
DEFAULT_CSS = """
|
|
25
|
+
PasswordInput {
|
|
26
|
+
width: 1fr;
|
|
27
|
+
height: auto;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
PasswordInput > Horizontal {
|
|
31
|
+
width: auto;
|
|
32
|
+
height: auto;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
PasswordInput CustomInput {
|
|
36
|
+
width: 1fr;
|
|
37
|
+
margin-right: 0;
|
|
38
|
+
border-right: none;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
PasswordInput CustomInput:focus {
|
|
42
|
+
border-right: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
PasswordInput Button {
|
|
47
|
+
width: auto;
|
|
48
|
+
margin-left: 0;
|
|
49
|
+
border-left: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
class Changed(Message):
|
|
55
|
+
"""
|
|
56
|
+
Sent when value changed.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(self, input: 'PasswordInput', value: str):
|
|
60
|
+
super().__init__()
|
|
61
|
+
self.input = input
|
|
62
|
+
self.value = value
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def control(self) -> 'PasswordInput':
|
|
66
|
+
return self.input
|
|
67
|
+
|
|
68
|
+
class Shown(Message):
|
|
69
|
+
"""
|
|
70
|
+
Sent when the value becomes visible.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
def __init__(self, input: 'PasswordInput') -> None:
|
|
74
|
+
super().__init__()
|
|
75
|
+
self.input = input
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def control(self) -> 'PasswordInput':
|
|
79
|
+
return self.input
|
|
80
|
+
|
|
81
|
+
class Hidden(Message):
|
|
82
|
+
"""
|
|
83
|
+
Sent when the value becomes hidden.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
def __init__(self, input: 'PasswordInput') -> None:
|
|
87
|
+
super().__init__()
|
|
88
|
+
self.input = input
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def control(self) -> 'PasswordInput':
|
|
92
|
+
return self.input
|
|
93
|
+
|
|
94
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
95
|
+
super().__init__(
|
|
96
|
+
id=kwargs.pop('id', None), classes=kwargs.pop('classes', None)
|
|
97
|
+
)
|
|
98
|
+
kwargs.pop('password', None)
|
|
99
|
+
self._input_args = args
|
|
100
|
+
self._input_kwargs = kwargs
|
|
101
|
+
|
|
102
|
+
def compose(self) -> ComposeResult:
|
|
103
|
+
with Horizontal():
|
|
104
|
+
yield CustomInput(
|
|
105
|
+
*self._input_args,
|
|
106
|
+
**self._input_kwargs,
|
|
107
|
+
password=True,
|
|
108
|
+
id='value',
|
|
109
|
+
)
|
|
110
|
+
yield Button(
|
|
111
|
+
_Icon.SHOW, tooltip=_Tooltip.SHOW, id='toggle-visibility'
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def on_mount(self) -> None:
|
|
115
|
+
self.value_input = self.query_one('#value', CustomInput)
|
|
116
|
+
self.toggle_visibility_button = self.query_one(
|
|
117
|
+
'#toggle-visibility', Button
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def show(self) -> None:
|
|
121
|
+
self.value_input.password = False
|
|
122
|
+
self.toggle_visibility_button.label = _Icon.HIDE
|
|
123
|
+
self.toggle_visibility_button.tooltip = _Tooltip.HIDE
|
|
124
|
+
self.post_message(message=self.Hidden(input=self))
|
|
125
|
+
|
|
126
|
+
def hide(self) -> None:
|
|
127
|
+
self.value_input.password = True
|
|
128
|
+
self.toggle_visibility_button.label = _Icon.SHOW
|
|
129
|
+
self.toggle_visibility_button.tooltip = _Tooltip.SHOW
|
|
130
|
+
self.post_message(message=self.Shown(input=self))
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def value(self) -> str:
|
|
134
|
+
return self.value_input.value
|
|
135
|
+
|
|
136
|
+
@value.setter
|
|
137
|
+
def value(self, value: str) -> None:
|
|
138
|
+
self.value_input.value = value
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def shown(self) -> bool:
|
|
142
|
+
return self.value_input.password is False
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def hidden(self) -> bool:
|
|
146
|
+
return not self.shown
|
|
147
|
+
|
|
148
|
+
@on(CustomInput.Changed, '#value')
|
|
149
|
+
def _on_value_changed(self, message: CustomInput.Changed) -> None:
|
|
150
|
+
self.post_message(
|
|
151
|
+
message=self.Changed(input=self, value=message.value)
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
@on(Button.Pressed, '#toggle-visibility')
|
|
155
|
+
def _on_toggle_visibility(self, message: Button.Pressed) -> None:
|
|
156
|
+
if self.value_input.password is False:
|
|
157
|
+
self.hide()
|
|
158
|
+
elif self.value_input.password is True:
|
|
159
|
+
self.show()
|
|
160
|
+
|
|
161
|
+
self.value_input.focus()
|
restiny/widgets/path_chooser.py
CHANGED
|
@@ -9,10 +9,10 @@ from textual.message import Message
|
|
|
9
9
|
from textual.reactive import Reactive
|
|
10
10
|
from textual.screen import ModalScreen
|
|
11
11
|
from textual.widget import Widget
|
|
12
|
-
from textual.widgets import Button,
|
|
12
|
+
from textual.widgets import Button, Label, Switch
|
|
13
13
|
|
|
14
14
|
from restiny.utils import filter_paths
|
|
15
|
-
from restiny.widgets import CustomDirectoryTree
|
|
15
|
+
from restiny.widgets import CustomDirectoryTree, CustomInput
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class PathChooserScreen(ModalScreen):
|
|
@@ -53,7 +53,7 @@ class PathChooserScreen(ModalScreen):
|
|
|
53
53
|
yield CustomDirectoryTree(path='/')
|
|
54
54
|
|
|
55
55
|
with Horizontal(classes='w-auto h-auto mt-1'):
|
|
56
|
-
yield
|
|
56
|
+
yield CustomInput(
|
|
57
57
|
placeholder='--empty--',
|
|
58
58
|
select_on_focus=False,
|
|
59
59
|
disabled=True,
|
|
@@ -74,7 +74,7 @@ class PathChooserScreen(ModalScreen):
|
|
|
74
74
|
'#option-show-hidden-dirs'
|
|
75
75
|
)
|
|
76
76
|
self.directory_tree = self.query_one(CustomDirectoryTree)
|
|
77
|
-
self.input = self.query_one(
|
|
77
|
+
self.input = self.query_one(CustomInput)
|
|
78
78
|
self.btn_cancel = self.query_one('#cancel')
|
|
79
79
|
self.btn_confirm = self.query_one('#choose')
|
|
80
80
|
|
|
@@ -197,7 +197,7 @@ class PathChooser(Widget):
|
|
|
197
197
|
grid-columns: 1fr auto;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
PathChooser >
|
|
200
|
+
PathChooser > CustomInput {
|
|
201
201
|
margin-right: 0;
|
|
202
202
|
border-right: none;
|
|
203
203
|
}
|
|
@@ -214,7 +214,7 @@ class PathChooser(Widget):
|
|
|
214
214
|
"""
|
|
215
215
|
|
|
216
216
|
def __init__(
|
|
217
|
-
self, path_chooser: PathChooser, path: Path | None
|
|
217
|
+
self, path_chooser: 'PathChooser', path: Path | None
|
|
218
218
|
) -> None:
|
|
219
219
|
super().__init__()
|
|
220
220
|
self.path_chooser = path_chooser
|
|
@@ -241,7 +241,7 @@ class PathChooser(Widget):
|
|
|
241
241
|
) -> None:
|
|
242
242
|
super().__init__(*args, **kwargs)
|
|
243
243
|
self.path_type = path_type
|
|
244
|
-
self.
|
|
244
|
+
self._path = path
|
|
245
245
|
|
|
246
246
|
def compose(self) -> ComposeResult:
|
|
247
247
|
icon = ''
|
|
@@ -250,8 +250,8 @@ class PathChooser(Widget):
|
|
|
250
250
|
elif self.path_type == _PathType.DIR:
|
|
251
251
|
icon = ' 🗂 '
|
|
252
252
|
|
|
253
|
-
yield
|
|
254
|
-
self.
|
|
253
|
+
yield CustomInput(
|
|
254
|
+
str(self._path) if self._path else '',
|
|
255
255
|
placeholder='--empty--',
|
|
256
256
|
select_on_focus=False,
|
|
257
257
|
disabled=True,
|
|
@@ -260,7 +260,7 @@ class PathChooser(Widget):
|
|
|
260
260
|
yield Button(icon, tooltip=f'Choose {self.path_type}', id='choose')
|
|
261
261
|
|
|
262
262
|
def on_mount(self) -> None:
|
|
263
|
-
self.path_input = self.query_one('#path',
|
|
263
|
+
self.path_input = self.query_one('#path', CustomInput)
|
|
264
264
|
self.choose_button = self.query_one('#choose', Button)
|
|
265
265
|
|
|
266
266
|
@property
|
|
@@ -275,8 +275,8 @@ class PathChooser(Widget):
|
|
|
275
275
|
self.path_input.value = value
|
|
276
276
|
self.path_input.tooltip = value
|
|
277
277
|
|
|
278
|
-
@on(
|
|
279
|
-
def _on_path_changed(self, message:
|
|
278
|
+
@on(CustomInput.Changed, '#path')
|
|
279
|
+
def _on_path_changed(self, message: CustomInput.Changed) -> None:
|
|
280
280
|
self.post_message(
|
|
281
281
|
message=self.Changed(path_chooser=self, path=self.path)
|
|
282
282
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: restiny
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: A minimalist HTTP client, no bullshit
|
|
5
5
|
Author-email: Kalebe Chimanski de Almeida <kalebe.chi.almeida@gmail.com>
|
|
6
6
|
License: Apache License
|
|
@@ -216,7 +216,6 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
216
216
|
Classifier: Environment :: Console
|
|
217
217
|
Classifier: Typing :: Typed
|
|
218
218
|
Classifier: Programming Language :: Python :: 3
|
|
219
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
220
219
|
Classifier: Programming Language :: Python :: 3.11
|
|
221
220
|
Classifier: Programming Language :: Python :: 3.12
|
|
222
221
|
Classifier: Programming Language :: Python :: 3.13
|
|
@@ -228,17 +227,20 @@ Classifier: Operating System :: Microsoft :: Windows :: Windows 11
|
|
|
228
227
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
229
228
|
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
230
229
|
Classifier: Natural Language :: English
|
|
231
|
-
Requires-Python: >=3.
|
|
230
|
+
Requires-Python: >=3.11
|
|
232
231
|
Description-Content-Type: text/markdown
|
|
233
232
|
License-File: LICENSE
|
|
234
233
|
Requires-Dist: textual<6.4,>=6.3
|
|
235
234
|
Requires-Dist: textual[syntax]
|
|
236
235
|
Requires-Dist: httpx<0.29,>=0.28
|
|
237
236
|
Requires-Dist: pyperclip<1.10,>=1.9
|
|
237
|
+
Requires-Dist: sqlalchemy<3.0,>=2.0
|
|
238
|
+
Requires-Dist: pydantic<2.13,>=2.12
|
|
238
239
|
Dynamic: license-file
|
|
239
240
|
|
|
240
241
|

|
|
241
|
-

|
|
243
|
+
|
|
242
244
|
|
|
243
245
|
|
|
244
246
|
- [RESTiny](#restiny)
|
|
@@ -254,7 +256,7 @@ Dynamic: license-file
|
|
|
254
256
|
|
|
255
257
|
_A minimal, elegant HTTP client for Python — with a TUI interface powered by [Textual](https://github.com/Textualize/textual)._
|
|
256
258
|
|
|
257
|
-

|
|
258
260
|
|
|
259
261
|
## How to install
|
|
260
262
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
restiny/__about__.py,sha256=gd3s3RotD0_KL90Tua-YkOr60Jm2C2_wvlEhAT08068,22
|
|
2
|
+
restiny/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
restiny/__main__.py,sha256=XkZbw04fLAFImx-T5me4CcZRsKdr33eUaWUKZ2kZPR8,1165
|
|
4
|
+
restiny/consts.py,sha256=LMwWVmOrOwZAKcnpZkBs-duMDE6QWTWD4un9y6hcVEc,11319
|
|
5
|
+
restiny/entities.py,sha256=ibQLSNxBj_mqTPyrkI_VnOVCpUETK6sZMAXhNKBDo4c,14232
|
|
6
|
+
restiny/enums.py,sha256=57KQPeY1YFNr15Ykr8ZglkEKdez6Djqnfzm0YaBPGfQ,996
|
|
7
|
+
restiny/httpx_auths.py,sha256=FqwO6W2AYNhmG5OEbQBusumH-zVvel4A8Oa7c4cbm-4,1295
|
|
8
|
+
restiny/utils.py,sha256=ktXrnlujBYxrPi-nDYor94r1cmJ07xyezesuZESswOc,4493
|
|
9
|
+
restiny/assets/__init__.py,sha256=JL1KARlToF6ZR7KeUjlDAHgwwVM2qXYaIl4wHeFW2zU,93
|
|
10
|
+
restiny/assets/style.tcss,sha256=bpPEiBcKFE5eREae_f4VbGrhdObqrtiYcDROROGiLCI,978
|
|
11
|
+
restiny/data/db.py,sha256=aRYrjv0ecFWToj5Y0XBJ_o4QPLPY2qzRKvgUgbzG98E,1990
|
|
12
|
+
restiny/data/models.py,sha256=BlwQNS2X6t5Fkt9ioowXpWYKgm3_joYvOWgp69BILJ0,3392
|
|
13
|
+
restiny/data/repos.py,sha256=Bn-zH2UwNG_hbxnPfZzyiCg3O7nMe5O__b37pRtXsoY,15840
|
|
14
|
+
restiny/data/sql/__init__.py,sha256=4Erfs-MC_ctZ53lXqe_FQwJDRd8SrxGrZ3_rG8o7VCU,81
|
|
15
|
+
restiny/ui/__init__.py,sha256=ak-HZ1y5w5E1s2ojBAicdP2GwBwjz9PRDdegusf5ZpE,439
|
|
16
|
+
restiny/ui/app.py,sha256=nhE7kp9_SP2TifVGmFTzJVmk0L3kWYqXt0TTo9h95xw,20931
|
|
17
|
+
restiny/ui/collections_area.py,sha256=Vk8WSP8zP0hRj4K46zPxziDqMK2kpc2pr87_b8uAFwk,19451
|
|
18
|
+
restiny/ui/environments_screen.py,sha256=rcKymFxWYP9vxLIPwwq2cxPnI1idueDVB3fLQMClHeA,9573
|
|
19
|
+
restiny/ui/request_area.py,sha256=xHsyaJ2P5CsMDRspuNjefJCI3KNdZxWs0ir9eLoZXjA,21668
|
|
20
|
+
restiny/ui/response_area.py,sha256=3KHqFADeCWttd5WKbqA4l_6q9AiKTKbQXt2FMAUvsw4,4246
|
|
21
|
+
restiny/ui/settings_screen.py,sha256=L_i2WFqqrCFkucZLXeg-kVXLzP7jZ-CTS65T1bdq3ZU,2249
|
|
22
|
+
restiny/ui/top_bar_area.py,sha256=6vKhlx_eJpgpH3EeConKxky03RRmGizMGwgPrG0DkkU,1583
|
|
23
|
+
restiny/ui/url_area.py,sha256=PIcH9ef0q7gEfLZ149CNtTr2NgAeKESLuIl0e5Pt4hg,3868
|
|
24
|
+
restiny/widgets/__init__.py,sha256=RaU2JkRWAoJULG3rpPtMNUarPU6Yu6gJwzAsSad2hgg,895
|
|
25
|
+
restiny/widgets/collections_tree.py,sha256=UVtG6km49G-DjklpXHoADaTvj0L1-FWOLkz7gijGU2g,2144
|
|
26
|
+
restiny/widgets/confirm_prompt.py,sha256=1xdCaJZUDzV4-fQ1ztbe7uX9hJ6ZZUBghtwgReBHz9w,2147
|
|
27
|
+
restiny/widgets/custom_directory_tree.py,sha256=sNTaI0DBAO56MyOy6qMZPgWXiTUQbBrJdn1GtOdxrDc,1268
|
|
28
|
+
restiny/widgets/custom_input.py,sha256=W6gE9jbTl_R1uLSA5Dz9eBX7aNID2-rYZP3j2oNi4SA,466
|
|
29
|
+
restiny/widgets/custom_text_area.py,sha256=ykmG-6MiMhz6BqNzP8f14jUTWWKjsCOIEhgciP-01Y8,14032
|
|
30
|
+
restiny/widgets/dynamic_fields.py,sha256=S2epm-_QOsHEGhVFwDlOvIqOQkUgpGnh6pK3_JoTQ1g,16104
|
|
31
|
+
restiny/widgets/password_input.py,sha256=xXOfiStcUCbP_cnrS2Rz0-GmsvmOsen4G41zOpmjLD8,4057
|
|
32
|
+
restiny/widgets/path_chooser.py,sha256=FdG9fdgY2qD8o-7aBn8F005f8H91kbYtyF99RRGLRas,9273
|
|
33
|
+
restiny-0.6.1.dist-info/licenses/LICENSE,sha256=Z190MKguypkrjaCldiorEbMmBQp7ylvx09oyE4oDCTs,11361
|
|
34
|
+
restiny-0.6.1.dist-info/METADATA,sha256=OO4PshKvwwwyCx62RfI112o1qnIiP7bE1lLWde0E_H8,16137
|
|
35
|
+
restiny-0.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
restiny-0.6.1.dist-info/entry_points.txt,sha256=F9zW8bAPAwIihltqjzYow4ahmH_B6VkAHzQFA-8QOn4,50
|
|
37
|
+
restiny-0.6.1.dist-info/top_level.txt,sha256=1MQ_Q-fV1Dwbu4zU3g1Eg-CfRgC412X-mvMIrEdrlbk,8
|
|
38
|
+
restiny-0.6.1.dist-info/RECORD,,
|
restiny/core/__init__.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module contains the specific sections of the DataFox user interface (UI).
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from restiny.core.request_area import RequestArea, RequestAreaData
|
|
6
|
-
from restiny.core.response_area import ResponseArea
|
|
7
|
-
from restiny.core.url_area import URLArea, URLAreaData
|
|
8
|
-
|
|
9
|
-
__all__ = [
|
|
10
|
-
'RequestArea',
|
|
11
|
-
'RequestAreaData',
|
|
12
|
-
'ResponseArea',
|
|
13
|
-
'URLArea',
|
|
14
|
-
'URLAreaData',
|
|
15
|
-
]
|