updated bacloud

This commit is contained in:
Eric Froemling 2020-02-05 20:18:59 -08:00
parent b86b38c901
commit 7a60fb9b1a
3 changed files with 48 additions and 28 deletions

View File

@ -30,7 +30,7 @@ from efro.entity._value import CompoundValue
from efro.jsonutils import ExtendedJSONEncoder, ExtendedJSONDecoder
if TYPE_CHECKING:
from typing import Dict, Any, Type, Union
from typing import Dict, Any, Type, Union, Optional
T = TypeVar('T', bound='EntityMixin')
@ -133,24 +133,38 @@ class EntityMixin:
self.prune_fields_data(data)
return data
def to_json_str(self, prune: bool = True, pretty: bool = False) -> str:
def to_json_str(self,
prune: bool = True,
pretty: bool = False,
sort_keys_override: Optional[bool] = None) -> str:
"""Convert the entity to a json string.
This uses efro.jsontools.ExtendedJSONEncoder/Decoder
to support data types not natively storable in json.
Be sure to use the corresponding loading functions here for
this same reason.
By default, keys are sorted when pretty-printing and not otherwise,
but this can be overridden by passing a bool as sort_keys_override.
"""
if prune:
data = self.pruned_data()
else:
data = self.d_data
if pretty:
return json.dumps(data,
indent=2,
sort_keys=True,
cls=ExtendedJSONEncoder)
return json.dumps(data, separators=(',', ':'), cls=ExtendedJSONEncoder)
return json.dumps(
data,
indent=2,
sort_keys=(sort_keys_override
if sort_keys_override is not None else True),
cls=ExtendedJSONEncoder)
# When not doing pretty, go for quick and compact.
return json.dumps(
data,
separators=(',', ':'),
sort_keys=(sort_keys_override
if sort_keys_override is not None else False),
cls=ExtendedJSONEncoder)
@staticmethod
def json_loads(s: str) -> Any:

View File

@ -1,6 +1,6 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<!--DOCSHASH=c16f4e560c92e537cd19a323b815765c-->
<h4><em>last updated on 2020-02-04 for Ballistica version 1.5.0 build 20001</em></h4>
<!--DOCSHASH=a17e7abfc5ab7bf18ceac832fb0825ea-->
<h4><em>last updated on 2020-02-05 for Ballistica version 1.5.0 build 20001</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr>

View File

@ -71,11 +71,12 @@ class Response:
Attributes:
message: If present, client should print this message before any other
response processing (including error handling) occurs.
message_end: end arg for message print() call.
error: If present, client should abort with this error message.
login: If present, a token that should be stored client-side and passed
with subsequent commands.
logout: If True, any existing client-side token should be discarded.
dirmanifest: If present, client should generate a manifest of this dir.
dir_manifest: If present, client should generate a manifest of this dir.
It should be added to endcommand args as 'manifest'.
uploads: If present, client should upload the requested files (arg1)
individually to a server command (arg2) with provided args (arg3).
@ -86,25 +87,28 @@ class Response:
be written to the client. This should only be used for relatively
small files as they are all included inline as part of the response.
deletes: If present, file paths that should be deleted on the client.
dirpruneempty: If present, all empty dirs under this one should be
dir_prune_empty: If present, all empty dirs under this one should be
removed.
endmessage: If present, a message that should be printed after all other
end_message: If present, a message that should be printed after all other
response processing is done.
endcommand: If present, this command is run with these args at the end
end_message_end: end arg for end_message print() call.
end_command: If present, this command is run with these args at the end
of response processing.
"""
message: Optional[str] = None
message_end: str = '\n'
error: Optional[str] = None
login: Optional[str] = None
logout: bool = False
dirmanifest: Optional[str] = None
dir_manifest: Optional[str] = None
uploads: Optional[Tuple[List[str], str, Dict]] = None
uploads_inline: Optional[List[str]] = None
downloads_inline: Optional[Dict[str, str]] = None
deletes: Optional[List[str]] = None
dirpruneempty: Optional[str] = None
endmessage: Optional[str] = None
endcommand: Optional[Tuple[str, Dict]] = None
dir_prune_empty: Optional[str] = None
end_message: Optional[str] = None
end_message_end: str = '\n'
end_command: Optional[Tuple[str, Dict]] = None
class CleanError(Exception):
@ -271,7 +275,7 @@ class App:
# Handle a few things inline.
# (so this functionality is available even to recursive commands, etc.)
if response.message is not None:
print(response.message, flush=True)
print(response.message, end=response.message_end, flush=True)
if response.error is not None:
raise CleanError(response.error)
@ -294,7 +298,7 @@ class App:
files=putfiles,
)
def _handle_dirmanifest_response(self, dirmanifest: str) -> None:
def _handle_dir_manifest_response(self, dirmanifest: str) -> None:
from dataclasses import asdict
manifest = DirManifest.load_from_disk(Path(dirmanifest))
@ -357,7 +361,7 @@ class App:
files[filepath] = data_base64
self._end_command_args['uploads_inline'] = files
def _handle_dirpruneempty(self, prunedir: str) -> None:
def _handle_dir_prune_empty(self, prunedir: str) -> None:
"""Handle pruning empty directories."""
# Walk the tree bottom-up so we can properly kill recursive empty dirs.
for basename, dirnames, filenames in os.walk(prunedir, topdown=False):
@ -385,8 +389,8 @@ class App:
self._state.login_token = response.login
if response.logout:
self._state.login_token = None
if response.dirmanifest is not None:
self._handle_dirmanifest_response(response.dirmanifest)
if response.dir_manifest is not None:
self._handle_dir_manifest_response(response.dir_manifest)
if response.uploads_inline is not None:
self._handle_uploads_inline(response.uploads_inline)
if response.uploads is not None:
@ -395,12 +399,14 @@ class App:
self._handle_downloads_inline(response.downloads_inline)
if response.deletes:
self._handle_deletes(response.deletes)
if response.dirpruneempty:
self._handle_dirpruneempty(response.dirpruneempty)
if response.endmessage is not None:
print(response.endmessage, flush=True)
if response.endcommand is not None:
nextcall = response.endcommand
if response.dir_prune_empty:
self._handle_dir_prune_empty(response.dir_prune_empty)
if response.end_message is not None:
print(response.end_message,
end=response.end_message_end,
flush=True)
if response.end_command is not None:
nextcall = response.end_command
for key, val in self._end_command_args.items():
nextcall[1][key] = val