dfpyre 0.6.3__py3-none-any.whl → 0.7.0__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.

Potentially problematic release.


This version of dfpyre might be problematic. Click here for more details.

dfpyre/items.py CHANGED
@@ -4,19 +4,28 @@ Contains class definitions for code items.
4
4
 
5
5
  from enum import Enum
6
6
  import re
7
- from typing import Literal, Dict, Any
7
+ from typing import Literal, Any
8
8
  from dfpyre.style import is_ampersand_coded, ampersand_to_minimessage
9
+ from dfpyre.util import PyreException, warn
9
10
  from mcitemlib.itemlib import Item as NbtItem
10
11
 
11
12
 
12
13
  NUMBER_REGEX = r'-?\d*\.?\d+'
14
+ VAR_SHORTHAND_CHAR = '$'
15
+ VAR_SCOPES = {'g': 'unsaved', 's': 'saved', 'l': 'local', 'i': 'line'}
13
16
 
14
17
 
15
- class PyreException(Exception):
16
- pass
18
+ def convert_argument(arg: Any):
19
+ if type(arg) in {int, float}:
20
+ return num(arg)
21
+ elif isinstance(arg, str):
22
+ if len(arg) > 2 and arg[0] == VAR_SHORTHAND_CHAR and arg[1] in VAR_SCOPES:
23
+ return var(arg[2:], VAR_SCOPES[arg[1]])
24
+ return text(arg)
25
+ return arg
17
26
 
18
27
 
19
- def _add_slot(d: Dict, slot: int|None):
28
+ def _add_slot(d: dict, slot: int|None):
20
29
  if slot is not None:
21
30
  d['slot'] = slot
22
31
 
@@ -274,7 +283,7 @@ class parameter:
274
283
  self.optional = optional
275
284
  self.description = description
276
285
  self.note = note
277
- self.default_value = default_value
286
+ self.default_value = convert_argument(default_value)
278
287
 
279
288
 
280
289
  def format(self, slot: int):
@@ -292,8 +301,13 @@ class parameter:
292
301
  formatted_dict['item']['data']['description'] = self.description
293
302
  if self.note:
294
303
  formatted_dict['item']['data']['note'] = self.note
295
- if self.default_value is not None and not self.plural and self.optional:
296
- formatted_dict['item']['data']['default_value'] = self.default_value.format(None)['item']
304
+ if self.default_value is not None:
305
+ if not self.optional:
306
+ warn(f'For parameter "{self.name}": Default value cannot be set if optional is False.')
307
+ elif self.plural:
308
+ warn(f'For parameter "{self.name}": Default value cannot be set while plural is True.')
309
+ else:
310
+ formatted_dict['item']['data']['default_value'] = self.default_value.format(None)['item']
297
311
 
298
312
  return formatted_dict
299
313
 
@@ -311,7 +325,7 @@ def _some_or(value: Any, none_value: Any):
311
325
  return value
312
326
 
313
327
 
314
- def item_from_dict(item_dict: Dict) -> object:
328
+ def item_from_dict(item_dict: dict) -> object:
315
329
  item_id = item_dict['id']
316
330
  item_data = item_dict['data']
317
331
 
dfpyre/pyre.py CHANGED
@@ -4,25 +4,18 @@ A package for externally creating code templates for the DiamondFire Minecraft s
4
4
  By Amp
5
5
  """
6
6
 
7
- import base64
8
- import gzip
9
7
  import json
10
- import os
11
8
  from difflib import get_close_matches
12
9
  import datetime
13
- from typing import Tuple, List, Dict
10
+ from typing import Tuple
14
11
  from enum import Enum
15
12
  import socket
16
13
  from mcitemlib.itemlib import Item as NbtItem
14
+ from dfpyre.util import *
17
15
  from dfpyre.items import *
18
16
  from dfpyre.scriptgen import generate_script, GeneratorFlags
17
+ from dfpyre.actiondump import CODEBLOCK_DATA, get_default_tags
19
18
 
20
- COL_WARN = '\x1b[33m'
21
- COL_RESET = '\x1b[0m'
22
- COL_SUCCESS = '\x1b[32m'
23
- COL_ERROR = '\x1b[31m'
24
-
25
- CODEBLOCK_DATA_PATH = os.path.join(os.path.dirname(__file__), 'data/data.json')
26
19
 
27
20
  VARIABLE_TYPES = {'txt', 'comp', 'num', 'item', 'loc', 'var', 'snd', 'part', 'pot', 'g_val', 'vec', 'pn_el'}
28
21
  TEMPLATE_STARTERS = {'event', 'entity_event', 'func', 'process'}
@@ -31,9 +24,6 @@ SINGLE_NAME_CODEBLOCKS = {'func', 'process', 'call_func', 'start_process', 'else
31
24
  TARGETS = ['Selection', 'Default', 'Killer', 'Damager', 'Shooter', 'Victim', 'AllPlayers', 'Projectile', 'AllEntities', 'AllMobs', 'LastEntity']
32
25
  TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
33
26
 
34
- VAR_SHORTHAND_CHAR = '$'
35
- VAR_SCOPES = {'g': 'unsaved', 's': 'saved', 'l': 'local', 'i': 'line'}
36
-
37
27
  CODECLIENT_URL = 'ws://localhost:31375'
38
28
 
39
29
 
@@ -57,54 +47,59 @@ DEFAULT_TARGET = Target.SELECTION
57
47
 
58
48
 
59
49
  class CodeBlock:
60
- def __init__(self, name: str, args: Tuple=(), target: Target=DEFAULT_TARGET, data: Dict={}):
50
+ def __init__(self, name: str, args: Tuple=(), target: Target=DEFAULT_TARGET, data: dict={}, tags: dict[str, str]={}):
61
51
  self.name = name
62
52
  self.args = args
63
53
  self.target = target
64
54
  self.data = data
55
+ self.tags = tags
65
56
 
66
57
  def __repr__(self) -> str:
67
58
  if self.name in SINGLE_NAME_CODEBLOCKS:
68
59
  if self.name == 'else':
69
60
  return 'CodeBlock(else)'
70
61
  return f'CodeBlock({self.name}, {self.data["data"]})'
71
- elif 'block' in self.data:
62
+ if 'block' in self.data:
72
63
  return f'CodeBlock({self.data["block"]}, {self.name})'
73
64
  return f'CodeBlock(bracket, {self.data["type"]}, {self.data["direct"]})'
74
65
 
75
-
76
- def _warn(message):
77
- print(f'{COL_WARN}! WARNING ! {message}{COL_RESET}')
66
+ def build(self, include_tags: bool=True) -> dict:
67
+ """
68
+ Builds a properly formatted block from a CodeBlock object.
69
+ """
70
+ built_block = self.data.copy()
71
+ codeblock_type = self.data.get('block')
72
+
73
+ # add target if necessary ('Selection' is the default when 'target' is blank)
74
+ if codeblock_type in TARGET_CODEBLOCKS and self.target != DEFAULT_TARGET:
75
+ built_block['target'] = self.target.get_string_value()
76
+
77
+ # add items into args
78
+ final_args = [arg.format(slot) for slot, arg in enumerate(self.args) if arg.type in VARIABLE_TYPES]
79
+
80
+ # check for unrecognized name, add tags
81
+ if codeblock_type is not None: # for brackets
82
+ if self.name not in CODEBLOCK_DATA[codeblock_type]:
83
+ _warn_unrecognized_name(codeblock_type, self.name)
84
+ elif include_tags:
85
+ tags = _get_codeblock_tags(codeblock_type, self.name, self.tags)
86
+ if len(final_args) + len(tags) > 27:
87
+ final_args = final_args[:(27-len(tags))] # trim list if over 27 elements
88
+ final_args.extend(tags) # add tags to end
89
+
90
+ # if final_args:
91
+ built_block['args'] = {'items': final_args}
92
+ return built_block
78
93
 
79
94
 
80
95
  def _warn_unrecognized_name(codeblock_type: str, codeblock_name: str):
81
- close = get_close_matches(codeblock_name, TAGDATA[codeblock_type].keys())
96
+ close = get_close_matches(codeblock_name, CODEBLOCK_DATA[codeblock_type].keys())
82
97
  if close:
83
- _warn(f'Code block name "{codeblock_name}" not recognized. Did you mean "{close[0]}"?')
98
+ warn(f'Code block name "{codeblock_name}" not recognized. Did you mean "{close[0]}"?')
84
99
  else:
85
- _warn(f'Code block name "{codeblock_name}" not recognized. Try spell checking or retyping without spaces.')
100
+ warn(f'Code block name "{codeblock_name}" not recognized. Try spell checking or retyping without spaces.')
86
101
 
87
102
 
88
- def _load_codeblock_data() -> Tuple:
89
- tag_data = {}
90
- if os.path.exists(CODEBLOCK_DATA_PATH):
91
- with open(CODEBLOCK_DATA_PATH, 'r') as f:
92
- tag_data = json.load(f)
93
- else:
94
- _warn('data.json not found -- Item tags and error checking will not work.')
95
- return ({}, set(), set())
96
-
97
- del tag_data['meta']
98
-
99
- all_names = [x for l in [d.keys() for d in tag_data.values()] for x in l] # flatten list
100
- return (
101
- tag_data,
102
- set(tag_data['extras'].keys()),
103
- set(all_names)
104
- )
105
-
106
- TAGDATA, TAGDATA_EXTRAS_KEYS, ALL_CODEBLOCK_NAMES = _load_codeblock_data()
107
-
108
103
  def _add_inverted(data, inverted):
109
104
  """
110
105
  If inverted is true, add 'inverted': 'NOT' to data.
@@ -113,36 +108,48 @@ def _add_inverted(data, inverted):
113
108
  data['inverted'] = 'NOT'
114
109
 
115
110
 
116
- def _convert_data_types(args):
117
- converted_args = []
118
- for value in args:
119
- if type(value) in {int, float}:
120
- converted_args.append(num(value))
121
- elif type(value) is str:
122
- if len(value) > 2 and value[0] == VAR_SHORTHAND_CHAR and value[1] in VAR_SCOPES:
123
- var_object = var(value[2:], VAR_SCOPES[value[1]])
124
- converted_args.append(var_object)
125
- else:
126
- converted_args.append(text(value))
111
+ def _convert_args(args):
112
+ return tuple(map(convert_argument, args))
113
+
114
+
115
+ def _check_applied_tags(tags: list[dict], applied_tags: dict[str, str], codeblock_name: str) -> dict[str, str]:
116
+ if len(applied_tags) > 0 and len(tags) == 0:
117
+ warn(f'Action "{codeblock_name}" does not have any tags, but still received {len(applied_tags)}.')
118
+ return {}
119
+ valid_tags = {}
120
+ tags_formatted = {t['name']: t for t in tags}
121
+ for name, option in applied_tags.items():
122
+ if name not in tags_formatted:
123
+ tag_names_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted.keys()))
124
+ warn(f'Tag "{name}" does not exist for action "{codeblock_name}". Available tags:\n{tag_names_joined}')
125
+ elif option not in tags_formatted[name]['options']:
126
+ options_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted[name]['options']))
127
+ warn(f'Tag "{name}" does not have the option "{option}". Available tag options:\n{options_joined}')
127
128
  else:
128
- converted_args.append(value)
129
- return tuple(converted_args)
129
+ valid_tags[name] = option
130
+ return valid_tags
130
131
 
131
132
 
132
- def _reformat_codeblock_tags(tags, codeblock_type: str, codeblock_name: str):
133
+ def _reformat_codeblock_tags(tags: list[dict], codeblock_type: str, codeblock_name: str, applied_tags: dict[str, str]):
133
134
  """
134
- Turns data.json tag items into DiamondFire formatted tag items
135
+ Turns tag objects into DiamondFire formatted tag items
135
136
  """
137
+
138
+ valid_applied_tags = _check_applied_tags(tags, applied_tags, codeblock_name)
136
139
  reformatted_tags = []
137
140
  for tag_item in tags:
138
- action_value = codeblock_name if 'action' not in tag_item else tag_item['action']
141
+ tag_name = tag_item['name']
142
+ tag_option = tag_item['default']
143
+ if tag_name in valid_applied_tags:
144
+ tag_option = valid_applied_tags[tag_name]
145
+
139
146
  new_tag_item = {
140
147
  'item': {
141
148
  'id': 'bl_tag',
142
149
  'data': {
143
- 'option': tag_item['option'],
144
- 'tag': tag_item['tag'],
145
- 'action': action_value,
150
+ 'option': tag_option,
151
+ 'tag': tag_name,
152
+ 'action': codeblock_name,
146
153
  'block': codeblock_type
147
154
  }
148
155
  },
@@ -152,57 +159,15 @@ def _reformat_codeblock_tags(tags, codeblock_type: str, codeblock_name: str):
152
159
  return reformatted_tags
153
160
 
154
161
 
155
- def _get_codeblock_tags(codeblock_type: str, codeblock_name: str):
162
+ def _get_codeblock_tags(codeblock_type: str, codeblock_name: str, applied_tags: dict[str, str]):
156
163
  """
157
164
  Get tags for the specified codeblock type and name
158
165
  """
159
- tags = None
160
- if codeblock_type in TAGDATA_EXTRAS_KEYS:
161
- tags = TAGDATA['extras'][codeblock_type]
162
- else:
163
- tags = TAGDATA[codeblock_type].get(codeblock_name)
164
- return _reformat_codeblock_tags(tags, codeblock_type, codeblock_name)
165
-
166
-
167
- def _build_block(codeblock: CodeBlock, include_tags: bool):
168
- """
169
- Builds a properly formatted block from a CodeBlock object.
170
- """
171
- built_block = codeblock.data.copy()
172
- codeblock_type = codeblock.data.get('block')
173
-
174
- # add target if necessary ('Selection' is the default when 'target' is blank)
175
- if codeblock_type in TARGET_CODEBLOCKS and codeblock.target != DEFAULT_TARGET:
176
- built_block['target'] = codeblock.target.get_string_value()
177
-
178
- # add items into args
179
- final_args = [arg.format(slot) for slot, arg in enumerate(codeblock.args) if arg.type in VARIABLE_TYPES]
180
-
181
- # check for unrecognized name, add tags
182
- if codeblock_type is not None: # for brackets
183
- if codeblock_type not in TAGDATA_EXTRAS_KEYS and codeblock.name not in ALL_CODEBLOCK_NAMES:
184
- _warn_unrecognized_name(codeblock_type, codeblock.name)
185
- elif include_tags:
186
- tags = _get_codeblock_tags(codeblock_type, codeblock.name)
187
- if len(final_args) + len(tags) > 27:
188
- final_args = final_args[:(27-len(tags))] # trim list if over 27 elements
189
- final_args.extend(tags) # add tags to end
190
-
191
- if final_args:
192
- built_block['args'] = {'items': final_args}
193
- return built_block
194
-
195
-
196
- def _df_encode(json_string: str) -> str:
197
- """
198
- Encodes a stringified json.
199
- """
200
- encoded_string = gzip.compress(json_string.encode('utf-8'))
201
- return base64.b64encode(encoded_string).decode('utf-8')
202
-
203
-
204
- def _df_decode(encoded_string: str) -> str:
205
- return gzip.decompress(base64.b64decode(encoded_string)).decode('utf-8')
166
+ action_data = CODEBLOCK_DATA[codeblock_type][codeblock_name]
167
+ if 'deprecatedNote' in action_data:
168
+ warn(f'Action "{codeblock_name}" is deprecated: {action_data["deprecatedNote"]}')
169
+ tags = action_data['tags']
170
+ return _reformat_codeblock_tags(tags, codeblock_type, codeblock_name, applied_tags)
206
171
 
207
172
 
208
173
  def _get_template_item(template_code: str, name: str, author: str) -> NbtItem:
@@ -232,7 +197,7 @@ class DFTemplate:
232
197
  Represents a DiamondFire code template.
233
198
  """
234
199
  def __init__(self, name: str=None, author: str='pyre'):
235
- self.codeblocks: List[CodeBlock] = []
200
+ self.codeblocks: list[CodeBlock] = []
236
201
  self.bracket_stack: list[str] = []
237
202
  self.name = name
238
203
  self.author = author
@@ -247,12 +212,16 @@ class DFTemplate:
247
212
  """
248
213
  Create a template object from an existing template code.
249
214
  """
250
- template_dict = json.loads(_df_decode(template_code))
215
+ template_dict = json.loads(df_decode(template_code))
251
216
  template = DFTemplate()
252
217
  for block_dict in template_dict['blocks']:
218
+ block_tags = get_default_tags(block_dict.get('block'), block_dict.get('action'))
253
219
  if 'args' in block_dict:
254
220
  args = []
255
221
  for item_dict in block_dict['args']['items']:
222
+ if item_dict['item'].get('id') == 'bl_tag':
223
+ tag_data = item_dict['item']['data']
224
+ block_tags[tag_data['tag']] = tag_data['option']
256
225
  parsed_item = item_from_dict(item_dict['item'])
257
226
  if parsed_item is not None:
258
227
  args.append(parsed_item)
@@ -267,7 +236,7 @@ class DFTemplate:
267
236
  if codeblock_name == 'bracket' or block_dict['block'] == 'else':
268
237
  codeblock = CodeBlock(codeblock_name, data=block_dict)
269
238
  else:
270
- codeblock = CodeBlock(codeblock_name, args, target, block_dict)
239
+ codeblock = CodeBlock(codeblock_name, args, target, block_dict, tags=block_tags)
271
240
  template.codeblocks.append(codeblock)
272
241
 
273
242
  return template
@@ -301,16 +270,16 @@ class DFTemplate:
301
270
  :param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
302
271
  :return: String containing encoded template data.
303
272
  """
304
- template_dict_blocks = [_build_block(codeblock, include_tags) for codeblock in self.codeblocks]
273
+ template_dict_blocks = [codeblock.build(include_tags) for codeblock in self.codeblocks]
305
274
  template_dict = {'blocks': template_dict_blocks}
306
275
  first_block = template_dict_blocks[0]
307
276
  if first_block['block'] not in TEMPLATE_STARTERS:
308
- _warn('Template does not start with an event, function, or process.')
277
+ warn('Template does not start with an event, function, or process.')
309
278
 
310
279
  self._set_template_name(first_block)
311
280
 
312
281
  json_string = json.dumps(template_dict, separators=(',', ':'))
313
- return _df_encode(json_string)
282
+ return df_encode(json_string)
314
283
 
315
284
 
316
285
  def build_and_send(self, method: Literal['recode', 'codeclient'], include_tags: bool=True) -> int:
@@ -355,78 +324,79 @@ class DFTemplate:
355
324
  self._add_codeblock(cmd, index)
356
325
 
357
326
 
358
- def function(self, name: str, *args, index: int|None=None):
359
- args = _convert_data_types(args)
360
- cmd = CodeBlock('func', args, data={'id': 'block', 'block': 'func', 'data': name})
327
+ def function(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
328
+ args = _convert_args(args)
329
+ cmd = CodeBlock('dynamic', args, data={'id': 'block', 'block': 'func', 'data': name}, tags=tags)
361
330
  self._add_codeblock(cmd, index)
362
331
 
363
332
 
364
- def process(self, name: str, *args, index: int|None=None):
365
- args = _convert_data_types(args)
366
- cmd = CodeBlock('process', args, data={'id': 'block', 'block': 'process', 'data': name})
333
+ def process(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
334
+ args = _convert_args(args)
335
+ cmd = CodeBlock('dynamic', args, data={'id': 'block', 'block': 'process', 'data': name}, tags=tags)
367
336
  self._add_codeblock(cmd, index)
368
337
 
369
338
 
370
339
  def call_function(self, name: str, *args, index: int|None=None):
371
- args = _convert_data_types(args)
372
- cmd = CodeBlock('call_func', args, data={'id': 'block', 'block': 'call_func', 'data': name})
340
+ args = _convert_args(args)
341
+ cmd = CodeBlock('dynamic', args, data={'id': 'block', 'block': 'call_func', 'data': name})
373
342
  self._add_codeblock(cmd, index)
374
343
 
375
- def start_process(self, name: str, index: int|None=None):
376
- cmd = CodeBlock('start_process', data={'id': 'block', 'block': 'start_process', 'data': name})
344
+
345
+ def start_process(self, name: str, tags: dict[str, str]={}, index: int|None=None):
346
+ cmd = CodeBlock('dynamic', data={'id': 'block', 'block': 'start_process', 'data': name}, tags=tags)
377
347
  self._add_codeblock(cmd, index)
378
348
 
379
349
 
380
- def player_action(self, name: str, *args, target: Target=DEFAULT_TARGET, index: int|None=None):
381
- args = _convert_data_types(args)
382
- cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'player_action', 'action': name})
350
+ def player_action(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, index: int|None=None):
351
+ args = _convert_args(args)
352
+ cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'player_action', 'action': name}, tags=tags)
383
353
  self._add_codeblock(cmd, index)
384
354
 
385
355
 
386
- def game_action(self, name: str, *args, index: int|None=None):
387
- args = _convert_data_types(args)
388
- cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'game_action', 'action': name})
356
+ def game_action(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
357
+ args = _convert_args(args)
358
+ cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'game_action', 'action': name}, tags=tags)
389
359
  self._add_codeblock(cmd, index)
390
360
 
391
361
 
392
- def entity_action(self, name: str, *args, target: Target=DEFAULT_TARGET, index: int|None=None):
393
- args = _convert_data_types(args)
394
- cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'entity_action', 'action': name})
362
+ def entity_action(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, index: int|None=None):
363
+ args = _convert_args(args)
364
+ cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'entity_action', 'action': name}, tags=tags)
395
365
  self._add_codeblock(cmd, index)
396
366
 
397
367
 
398
- def if_player(self, name: str, *args, target: Target=DEFAULT_TARGET, inverted: bool=False, index: int|None=None):
399
- args = _convert_data_types(args)
368
+ def if_player(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
369
+ args = _convert_args(args)
400
370
  data = {'id': 'block', 'block': 'if_player', 'action': name}
401
371
  _add_inverted(data, inverted)
402
- cmd = CodeBlock(name, args, target=target, data=data)
372
+ cmd = CodeBlock(name, args, target=target, data=data, tags=tags)
403
373
  self._add_codeblock(cmd, index)
404
374
  self._openbracket(index)
405
375
 
406
376
 
407
- def if_variable(self, name: str, *args, inverted: bool=False, index: int|None=None):
408
- args = _convert_data_types(args)
377
+ def if_variable(self, name: str, *args, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
378
+ args = _convert_args(args)
409
379
  data = {'id': 'block', 'block': 'if_var', 'action': name}
410
380
  _add_inverted(data, inverted)
411
- cmd = CodeBlock(name, args, data=data)
381
+ cmd = CodeBlock(name, args, data=data, tags=tags)
412
382
  self._add_codeblock(cmd, index)
413
383
  self._openbracket(index)
414
384
 
415
385
 
416
- def if_game(self, name: str, *args, inverted: bool=False, index: int|None=None):
417
- args = _convert_data_types(args)
386
+ def if_game(self, name: str, *args, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
387
+ args = _convert_args(args)
418
388
  data = {'id': 'block', 'block': 'if_game', 'action': name}
419
389
  _add_inverted(data, inverted)
420
- cmd = CodeBlock(name, args, data=data)
390
+ cmd = CodeBlock(name, args, data=data, tags=tags)
421
391
  self._add_codeblock(cmd, index)
422
392
  self._openbracket(index)
423
393
 
424
394
 
425
- def if_entity(self, name: str, *args, target: Target=DEFAULT_TARGET, inverted: bool=False, index: int|None=None):
426
- args = _convert_data_types(args)
395
+ def if_entity(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
396
+ args = _convert_args(args)
427
397
  data = {'id': 'block', 'block': 'if_entity', 'action': name}
428
398
  _add_inverted(data, inverted)
429
- cmd = CodeBlock(name, args, target=target, data=data)
399
+ cmd = CodeBlock(name, args, target=target, data=data, tags=tags)
430
400
  self._add_codeblock(cmd, index)
431
401
  self._openbracket(index)
432
402
 
@@ -437,37 +407,37 @@ class DFTemplate:
437
407
  self._openbracket(index)
438
408
 
439
409
 
440
- def repeat(self, name: str, *args, sub_action: str=None, index: int|None=None):
441
- args = _convert_data_types(args)
410
+ def repeat(self, name: str, *args, tags: dict[str, str]={}, sub_action: str=None, index: int|None=None):
411
+ args = _convert_args(args)
442
412
  data = {'id': 'block', 'block': 'repeat', 'action': name}
443
413
  if sub_action is not None:
444
414
  data['subAction'] = sub_action
445
- cmd = CodeBlock(name, args, data=data)
415
+ cmd = CodeBlock(name, args, data=data, tags=tags)
446
416
  self._add_codeblock(cmd, index)
447
417
  self._openbracket(index, 'repeat')
448
418
 
449
419
 
450
420
  def bracket(self, *args, index: int|None=None):
451
- args = _convert_data_types(args)
421
+ args = _convert_args(args)
452
422
  cmd = CodeBlock('bracket', data={'id': 'bracket', 'direct': 'close', 'type': self.bracket_stack.pop()})
453
423
  self._add_codeblock(cmd, index)
454
424
 
455
425
 
456
- def control(self, name: str, *args, index: int|None=None):
457
- args = _convert_data_types(args)
458
- cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'control', 'action': name})
426
+ def control(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
427
+ args = _convert_args(args)
428
+ cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'control', 'action': name}, tags=tags)
459
429
  self._add_codeblock(cmd, index)
460
430
 
461
431
 
462
- def select_object(self, name: str, *args, index: int|None=None):
463
- args = _convert_data_types(args)
464
- cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'select_obj', 'action': name})
432
+ def select_object(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
433
+ args = _convert_args(args)
434
+ cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'select_obj', 'action': name}, tags=tags)
465
435
  self._add_codeblock(cmd, index)
466
436
 
467
437
 
468
- def set_variable(self, name: str, *args, index: int|None=None):
469
- args = _convert_data_types(args)
470
- cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'set_var', 'action': name})
438
+ def set_variable(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
439
+ args = _convert_args(args)
440
+ cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'set_var', 'action': name}, tags=tags)
471
441
  self._add_codeblock(cmd, index)
472
442
 
473
443
 
@@ -481,6 +451,6 @@ class DFTemplate:
481
451
  :param bool var_shorthand: If True, all variables will be written using variable shorthand.
482
452
  """
483
453
  flags = GeneratorFlags(indent_size, literal_shorthand, var_shorthand)
484
- with open(output_path, 'w') as f:
454
+ with open(output_path, 'w', encoding='utf-8') as f:
485
455
  f.write(generate_script(self, flags))
486
456
 
dfpyre/scriptgen.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import dataclasses
2
2
  import re
3
3
  from dfpyre.items import *
4
+ from dfpyre.actiondump import get_default_tags
4
5
 
5
6
  SCRIPT_START = '''from dfpyre import *
6
7
  t = DFTemplate()
@@ -96,7 +97,7 @@ def argument_item_to_string(flags: GeneratorFlags, arg_item: object) -> str:
96
97
  if arg_item.optional:
97
98
  param_args.append('optional=True')
98
99
  if arg_item.default_value is not None:
99
- param_args.append(f'default_value={argument_item_to_string(arg_item.default_value)}')
100
+ param_args.append(f'default_value={argument_item_to_string(flags, arg_item.default_value)}')
100
101
  if arg_item.description:
101
102
  param_args.append(f'description="{arg_item.description}"')
102
103
  if arg_item.note:
@@ -114,6 +115,7 @@ def add_script_line(flags: GeneratorFlags, script_lines: list[str], indent_level
114
115
  script_lines.append(added_line)
115
116
 
116
117
 
118
+ # TODO: add tag values if not default
117
119
  def generate_script(template, flags: GeneratorFlags) -> str:
118
120
  indent_level = 0
119
121
  script_lines = []
@@ -140,7 +142,13 @@ def generate_script(template, flags: GeneratorFlags) -> str:
140
142
  method_args.extend(codeblock_args)
141
143
  if method_name in TARGET_CODEBLOCKS and codeblock.target.name != 'SELECTION':
142
144
  method_args.append(f'target=Target.{codeblock.target.name}')
145
+ if codeblock.tags:
146
+ print(codeblock.tags)
147
+ default_tags = get_default_tags(codeblock.data.get('block'), codeblock.name)
148
+ written_tags = {t: o for t, o in codeblock.tags.items() if default_tags[t] != o}
149
+ if written_tags:
150
+ method_args.append(f'tags={str(written_tags)}')
143
151
 
144
152
  line = f't.{method_name}({", ".join(method_args)})'
145
153
  add_script_line(flags, script_lines, indent_level, line)
146
- return SCRIPT_START + '\n'.join(script_lines)
154
+ return SCRIPT_START + '\n'.join(script_lines)
dfpyre/util.py ADDED
@@ -0,0 +1,28 @@
1
+ import base64
2
+ import gzip
3
+
4
+
5
+ COL_WARN = '\x1b[33m'
6
+ COL_RESET = '\x1b[0m'
7
+ COL_SUCCESS = '\x1b[32m'
8
+ COL_ERROR = '\x1b[31m'
9
+
10
+
11
+ class PyreException(Exception):
12
+ pass
13
+
14
+
15
+ def warn(message: str):
16
+ print(f'{COL_WARN}! WARNING ! {message}{COL_RESET}')
17
+
18
+
19
+ def df_encode(json_string: str) -> str:
20
+ """
21
+ Encodes a stringified json.
22
+ """
23
+ encoded_string = gzip.compress(json_string.encode('utf-8'))
24
+ return base64.b64encode(encoded_string).decode('utf-8')
25
+
26
+
27
+ def df_decode(encoded_string: str) -> str:
28
+ return gzip.decompress(base64.b64decode(encoded_string)).decode('utf-8')