mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-29 10:43:21 +08:00
C++ layer cleanup
This commit is contained in:
parent
a2bb5b9751
commit
5d7c72c365
@ -4132,16 +4132,16 @@
|
||||
"assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c",
|
||||
"assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb",
|
||||
"assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe",
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cd/cc/837483543f1d6b184f64b5e6a950",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/e6/d372324c7c08b5b300490fa5594e",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0e/11/3dda0974b64f51be4961628f572c",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cc/76/3f6356dd599091f5955ce349593b",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e1/23/3fe78cdef456a99140837ede7e49",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1c/bd/4c73637ee172630ee00145032ce7",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/a7/342bea2a6ec2f94d5de7bb52a59f",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/aa/24/5426cb7e6ca01b9e5d67ad3217b0",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cb/73/469fe3eb016f1e9c7f5c7811b182",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7c/fb/7e0880c1ab90b0484cdedc41c8ae",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f3/f2/097e861cf6ca981b18191e4c43b5",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6b/7c/8407f4a7326b8b19f3e187d3ffcb"
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1e/d6/ebdfb7bda48f2dec85c5df52ced9",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4a/0e/d344541dc2ae2a6eaf1024c99f7c",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/68/c3/fe2482149437800c83fed338140e",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/00/78f77d5ab9cc74a2f624f3a7253b",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ea/d1/017aaa42a7ace25a7b1f782632e5",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/b3/b149964180b661161e5f86109d99",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/97/177b59dcf24b839ca2d932200bb8",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/55/9edbc1eea06cf354fe37b50d68d2",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fc/ec/eb46555d63e5e3fd55497d1c1079",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/71/73/b8d329287a0a46cc8ed2ef08a7d9",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/62/79/66fc05a4388c4b5a9e9a7fd68a46",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c3/5d/eb6c20729c0572e717c907482205"
|
||||
}
|
||||
18
.idea/dictionaries/ericf.xml
generated
18
.idea/dictionaries/ericf.xml
generated
@ -262,6 +262,7 @@
|
||||
<w>centeuro</w>
|
||||
<w>centiseconds</w>
|
||||
<w>cfconfig</w>
|
||||
<w>cfenv</w>
|
||||
<w>cfgdir</w>
|
||||
<w>cfgkey</w>
|
||||
<w>cfgkeys</w>
|
||||
@ -280,6 +281,7 @@
|
||||
<w>charname</w>
|
||||
<w>charstr</w>
|
||||
<w>chatmessage</w>
|
||||
<w>cheadersline</w>
|
||||
<w>checkarg</w>
|
||||
<w>checkboxwidget</w>
|
||||
<w>checkenv</w>
|
||||
@ -323,6 +325,7 @@
|
||||
<w>codefilenames</w>
|
||||
<w>codefiles</w>
|
||||
<w>codehash</w>
|
||||
<w>codelines</w>
|
||||
<w>codeop</w>
|
||||
<w>collapsable</w>
|
||||
<w>collidemodel</w>
|
||||
@ -374,6 +377,7 @@
|
||||
<w>cpplintcode</w>
|
||||
<w>cpplintcodefull</w>
|
||||
<w>cpplintfull</w>
|
||||
<w>cpplintmodule</w>
|
||||
<w>cpuinfo</w>
|
||||
<w>cpus</w>
|
||||
<w>cpython</w>
|
||||
@ -398,6 +402,7 @@
|
||||
<w>cutscenes</w>
|
||||
<w>cval</w>
|
||||
<w>cwdg</w>
|
||||
<w>cxxabi</w>
|
||||
<w>cyaml</w>
|
||||
<w>cygwinccompiler</w>
|
||||
<w>darwiin</w>
|
||||
@ -750,6 +755,7 @@
|
||||
<w>genmapjson</w>
|
||||
<w>genstartercache</w>
|
||||
<w>genutils</w>
|
||||
<w>getaccountid</w>
|
||||
<w>getactivity</w>
|
||||
<w>getclass</w>
|
||||
<w>getcollide</w>
|
||||
@ -833,6 +839,7 @@
|
||||
<w>hatmotion</w>
|
||||
<w>hattach</w>
|
||||
<w>hdpi</w>
|
||||
<w>headercheckline</w>
|
||||
<w>headerregistry</w>
|
||||
<w>heapqmodule</w>
|
||||
<w>hehe</w>
|
||||
@ -960,6 +967,7 @@
|
||||
<w>keywd</w>
|
||||
<w>keywds</w>
|
||||
<w>khronos</w>
|
||||
<w>kickable</w>
|
||||
<w>kickin</w>
|
||||
<w>kickstart</w>
|
||||
<w>killcount</w>
|
||||
@ -987,6 +995,7 @@
|
||||
<w>lazybuilddir</w>
|
||||
<w>lbits</w>
|
||||
<w>lbld</w>
|
||||
<w>lbval</w>
|
||||
<w>lcfg</w>
|
||||
<w>lcolor</w>
|
||||
<w>lcrypto</w>
|
||||
@ -999,8 +1008,10 @@
|
||||
<w>levelmodule</w>
|
||||
<w>levelname</w>
|
||||
<w>lfull</w>
|
||||
<w>lfval</w>
|
||||
<w>libcrypto</w>
|
||||
<w>libegl</w>
|
||||
<w>libgen</w>
|
||||
<w>libinst</w>
|
||||
<w>liblzma</w>
|
||||
<w>libmain</w>
|
||||
@ -1034,6 +1045,7 @@
|
||||
<w>lintscriptsfast</w>
|
||||
<w>listobj</w>
|
||||
<w>listvalidconfigs</w>
|
||||
<w>lival</w>
|
||||
<w>llzma</w>
|
||||
<w>lmerged</w>
|
||||
<w>lmod</w>
|
||||
@ -1070,6 +1082,7 @@
|
||||
<w>lstart</w>
|
||||
<w>lstr</w>
|
||||
<w>lstrs</w>
|
||||
<w>lsval</w>
|
||||
<w>ltex</w>
|
||||
<w>lzma</w>
|
||||
<w>lzmamodule</w>
|
||||
@ -1208,6 +1221,7 @@
|
||||
<w>ndkpath</w>
|
||||
<w>neededsettings</w>
|
||||
<w>ness</w>
|
||||
<w>netlink</w>
|
||||
<w>nettesting</w>
|
||||
<w>netutils</w>
|
||||
<w>nevermind</w>
|
||||
@ -1576,6 +1590,7 @@
|
||||
<w>rsdr</w>
|
||||
<w>rsms</w>
|
||||
<w>rstr</w>
|
||||
<w>rtnetlink</w>
|
||||
<w>rtxt</w>
|
||||
<w>runmypy</w>
|
||||
<w>runonly</w>
|
||||
@ -1667,6 +1682,7 @@
|
||||
<w>sharedctypes</w>
|
||||
<w>sharedobj</w>
|
||||
<w>sharedobjs</w>
|
||||
<w>shellapi</w>
|
||||
<w>shiftdelay</w>
|
||||
<w>shiftposition</w>
|
||||
<w>shobs</w>
|
||||
@ -1792,6 +1808,8 @@
|
||||
<w>subrepos</w>
|
||||
<w>subsel</w>
|
||||
<w>subval</w>
|
||||
<w>subvalue</w>
|
||||
<w>subvaluetype</w>
|
||||
<w>successfull</w>
|
||||
<w>suiciding</w>
|
||||
<w>sunau</w>
|
||||
|
||||
@ -34,7 +34,7 @@ class AppDelegate:
|
||||
Category: App Classes
|
||||
"""
|
||||
|
||||
def create_default_game_config_ui(
|
||||
def create_default_game_settings_ui(
|
||||
self, gameclass: Type[ba.GameActivity],
|
||||
sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]],
|
||||
completion_call: Callable[[Optional[Dict[str, Any]]],
|
||||
@ -47,4 +47,4 @@ class AppDelegate:
|
||||
del gameclass, sessionclass, config, completion_call # unused
|
||||
from ba import _error
|
||||
_error.print_error(
|
||||
"create_default_game_config_ui needs to be overridden")
|
||||
"create_default_game_settings_ui needs to be overridden")
|
||||
|
||||
@ -103,8 +103,8 @@ class GameActivity(Activity[PlayerType, TeamType]):
|
||||
"""
|
||||
delegate = _ba.app.delegate
|
||||
assert delegate is not None
|
||||
delegate.create_default_game_config_ui(cls, sessionclass, settings,
|
||||
completion_call)
|
||||
delegate.create_default_game_settings_ui(cls, sessionclass, settings,
|
||||
completion_call)
|
||||
|
||||
@classmethod
|
||||
def get_score_info(cls) -> ba.ScoreInfo:
|
||||
|
||||
@ -32,7 +32,7 @@ if TYPE_CHECKING:
|
||||
class AppDelegate(ba.AppDelegate):
|
||||
"""Defines handlers for high level app functionality."""
|
||||
|
||||
def create_default_game_config_ui(
|
||||
def create_default_game_settings_ui(
|
||||
self, gameclass: Type[ba.GameActivity],
|
||||
sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]],
|
||||
completion_call: Callable[[Optional[Dict[str, Any]]],
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
"pytz",
|
||||
"yaml",
|
||||
"requests",
|
||||
"typing_extensions"
|
||||
"typing_extensions",
|
||||
"cpplint"
|
||||
],
|
||||
"python_paths": [
|
||||
"assets/src/ba_data/python",
|
||||
|
||||
@ -21,6 +21,9 @@ no_implicit_reexport = False
|
||||
[mypy-pylint.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-cpplint.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-xml.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||
<h4><em>last updated on 2020-05-31 for Ballistica version 1.5.0 build 20036</em></h4>
|
||||
<h4><em>last updated on 2020-06-01 for Ballistica version 1.5.0 build 20037</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>
|
||||
@ -1079,8 +1079,8 @@ manually.</p>
|
||||
|
||||
<h3>Methods:</h3>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_AppDelegate__create_default_game_config_ui">create_default_game_config_ui()</a></dt></h4><dd>
|
||||
<p><span>create_default_game_config_ui(self, gameclass: Type[<a href="#class_ba_GameActivity">ba.GameActivity</a>], sessionclass: Type[<a href="#class_ba_Session">ba.Session</a>], config: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], None]) -> None</span></p>
|
||||
<dt><h4><a name="method_ba_AppDelegate__create_default_game_settings_ui">create_default_game_settings_ui()</a></dt></h4><dd>
|
||||
<p><span>create_default_game_settings_ui(self, gameclass: Type[<a href="#class_ba_GameActivity">ba.GameActivity</a>], sessionclass: Type[<a href="#class_ba_Session">ba.Session</a>], config: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], None]) -> None</span></p>
|
||||
|
||||
<p>Launch a UI to configure the given game config.</p>
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import pytest
|
||||
@ -30,11 +30,12 @@ import pytest
|
||||
from efro.dataclasses import dataclass_assign, dataclass_validate
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Optional
|
||||
from typing import Optional, List
|
||||
|
||||
|
||||
def test_assign() -> None:
|
||||
"""Testing various assignments."""
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
@dataclass
|
||||
class _TestClass:
|
||||
@ -46,6 +47,10 @@ def test_assign() -> None:
|
||||
osval: Optional[str] = None
|
||||
obval: Optional[bool] = None
|
||||
ofval: Optional[float] = None
|
||||
lsval: List[str] = field(default_factory=list)
|
||||
lival: List[int] = field(default_factory=list)
|
||||
lbval: List[bool] = field(default_factory=list)
|
||||
lfval: List[float] = field(default_factory=list)
|
||||
|
||||
tclass = _TestClass()
|
||||
|
||||
@ -66,24 +71,39 @@ def test_assign() -> None:
|
||||
dataclass_assign(tclass, {'nonexistent': 'foo'})
|
||||
|
||||
# Correct types.
|
||||
dataclass_assign(tclass, {
|
||||
'ival': 1,
|
||||
'sval': 'foo',
|
||||
'bval': True,
|
||||
'fval': 2.0,
|
||||
})
|
||||
dataclass_assign(tclass, {
|
||||
'oival': None,
|
||||
'osval': None,
|
||||
'obval': None,
|
||||
'ofval': None,
|
||||
})
|
||||
dataclass_assign(tclass, {
|
||||
'oival': 1,
|
||||
'osval': 'foo',
|
||||
'obval': True,
|
||||
'ofval': 2.0,
|
||||
})
|
||||
dataclass_assign(
|
||||
tclass, {
|
||||
'ival': 1,
|
||||
'sval': 'foo',
|
||||
'bval': True,
|
||||
'fval': 2.0,
|
||||
'lsval': ['foo'],
|
||||
'lival': [10],
|
||||
'lbval': [False],
|
||||
'lfval': [1.0]
|
||||
})
|
||||
dataclass_assign(
|
||||
tclass, {
|
||||
'oival': None,
|
||||
'osval': None,
|
||||
'obval': None,
|
||||
'ofval': None,
|
||||
'lsval': [],
|
||||
'lival': [],
|
||||
'lbval': [],
|
||||
'lfval': []
|
||||
})
|
||||
dataclass_assign(
|
||||
tclass, {
|
||||
'oival': 1,
|
||||
'osval': 'foo',
|
||||
'obval': True,
|
||||
'ofval': 2.0,
|
||||
'lsval': ['foo', 'bar', 'eep'],
|
||||
'lival': [10, 11, 12],
|
||||
'lbval': [False, True],
|
||||
'lfval': [1.0, 2.0, 3.0]
|
||||
})
|
||||
|
||||
# Type mismatches.
|
||||
with pytest.raises(TypeError):
|
||||
@ -107,6 +127,21 @@ def test_assign() -> None:
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_assign(tclass, {'ofval': 'blah'})
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_assign(tclass, {'lsval': 'blah'})
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_assign(tclass, {'lsval': [1]})
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_assign(tclass, {'lbval': [None]})
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_assign(tclass, {'lival': ['foo']})
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_assign(tclass, {'lfval': [True]})
|
||||
|
||||
# More subtle ones (we currently require EXACT type matches)
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_assign(tclass, {'ival': True})
|
||||
@ -120,6 +155,9 @@ def test_assign() -> None:
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_assign(tclass, {'ofval': 1})
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
dataclass_assign(tclass, {'lfval': [1]})
|
||||
|
||||
|
||||
def test_validate() -> None:
|
||||
"""Testing validation."""
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -45,6 +45,14 @@ class ServerConfig:
|
||||
# be enabled unless you are hosting on a LAN with no internet connection.
|
||||
authenticate_clients: bool = True
|
||||
|
||||
# IDs of server admins. Server admins are not kickable through the default
|
||||
# kick vote system and they are able to kick players without a vote. To get
|
||||
# your account id, enter 'getaccountid' in settings->advanced->enter-code.
|
||||
admins: List[str] = field(default_factory=list)
|
||||
|
||||
# Whether the default kick-voting system is enabled.
|
||||
enable_default_kick_voting: bool = True
|
||||
|
||||
# UDP port to host on. Change this to work around firewalls or run multiple
|
||||
# servers on one machine.
|
||||
# 43210 is the default and the only port that will show up in the LAN
|
||||
|
||||
@ -33,7 +33,7 @@ from typing import TYPE_CHECKING
|
||||
from efro.terminal import Clr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import List, Sequence, Optional
|
||||
from typing import List, Sequence, Optional, Any
|
||||
|
||||
|
||||
# Python pip packages we require for this project.
|
||||
@ -612,7 +612,11 @@ def _get_server_config_template_yaml(projroot: str) -> str:
|
||||
assert vname.endswith(':')
|
||||
vname = vname[:-1]
|
||||
assert veq == '='
|
||||
vval = eval(vval_raw) # pylint: disable=eval-used
|
||||
vval: Any
|
||||
if vval_raw == 'field(default_factory=list)':
|
||||
vval = []
|
||||
else:
|
||||
vval = eval(vval_raw) # pylint: disable=eval-used
|
||||
|
||||
# Filter/override a few things.
|
||||
if vname == 'playlist_code':
|
||||
@ -621,7 +625,13 @@ def _get_server_config_template_yaml(projroot: str) -> str:
|
||||
elif vname == 'stats_url':
|
||||
vval = ('https://mystatssite.com/'
|
||||
'showstats?player=${ACCOUNT}')
|
||||
lines_out.append('#' + yaml.dump({vname: vval}).strip())
|
||||
elif vname == 'admins':
|
||||
vval = ['pb-yOuRAccOuNtIdHErE', 'pb-aNdMayBeAnotherHeRE']
|
||||
lines_out += [
|
||||
'#' + l for l in yaml.dump({
|
||||
vname: vval
|
||||
}).strip().splitlines()
|
||||
]
|
||||
else:
|
||||
# Convert comments referring to python bools to yaml bools.
|
||||
line = line.replace('True', 'true').replace('False', 'false')
|
||||
|
||||
@ -30,9 +30,9 @@ if TYPE_CHECKING:
|
||||
# For fields with these string types, we require a passed value's type
|
||||
# to exactly match one of the tuple values to consider the assignment valid.
|
||||
_SIMPLE_ASSIGN_TYPES: Dict[str, Tuple[Type, ...]] = {
|
||||
'bool': (bool, ),
|
||||
'str': (str, ),
|
||||
'int': (int, ),
|
||||
'str': (str, ),
|
||||
'bool': (bool, ),
|
||||
'float': (float, ),
|
||||
'Optional[int]': (int, type(None)),
|
||||
'Optional[str]': (str, type(None)),
|
||||
@ -40,6 +40,13 @@ _SIMPLE_ASSIGN_TYPES: Dict[str, Tuple[Type, ...]] = {
|
||||
'Optional[float]': (float, type(None)),
|
||||
}
|
||||
|
||||
_LIST_ASSIGN_TYPES: Dict[str, Tuple[Type, ...]] = {
|
||||
'List[int]': (int, ),
|
||||
'List[str]': (str, ),
|
||||
'List[bool]': (bool, ),
|
||||
'List[float]': (float, ),
|
||||
}
|
||||
|
||||
|
||||
def dataclass_assign(instance: Any, values: Dict[str, Any]) -> None:
|
||||
"""Safely assign values from a dict to a dataclass instance.
|
||||
@ -60,6 +67,22 @@ def dataclass_assign(instance: Any, values: Dict[str, Any]) -> None:
|
||||
the increased safety checks may be worth the speed tradeoff in some
|
||||
cases.
|
||||
"""
|
||||
_dataclass_validate(instance, values)
|
||||
for key, value in values.items():
|
||||
setattr(instance, key, value)
|
||||
|
||||
|
||||
def dataclass_validate(instance: Any) -> None:
|
||||
"""Ensure values in a dataclass are correct types.
|
||||
|
||||
Note that this will always fail if a dataclass contains field types
|
||||
not supported by this module.
|
||||
"""
|
||||
_dataclass_validate(instance, dataclasses.asdict(instance))
|
||||
|
||||
|
||||
def _dataclass_validate(instance: Any, values: Dict[str, Any]) -> None:
|
||||
# pylint: disable=too-many-branches
|
||||
if not dataclasses.is_dataclass(instance):
|
||||
raise TypeError(f'Passed instance {instance} is not a dataclass.')
|
||||
if not isinstance(values, dict):
|
||||
@ -82,10 +105,10 @@ def dataclass_assign(instance: Any, values: Dict[str, Any]) -> None:
|
||||
f' been created without "from __future__ import annotations";'
|
||||
f' those dataclasses are unsupported here.')
|
||||
|
||||
reqtypes = _SIMPLE_ASSIGN_TYPES.get(fieldtype)
|
||||
if reqtypes is not None:
|
||||
# pylint: disable=unidiomatic-typecheck
|
||||
if not any(type(value) is t for t in reqtypes):
|
||||
if fieldtype in _SIMPLE_ASSIGN_TYPES:
|
||||
reqtypes = _SIMPLE_ASSIGN_TYPES[fieldtype]
|
||||
valuetype = type(value)
|
||||
if not any(valuetype is t for t in reqtypes):
|
||||
if len(reqtypes) == 1:
|
||||
expected = reqtypes[0].__name__
|
||||
else:
|
||||
@ -93,23 +116,25 @@ def dataclass_assign(instance: Any, values: Dict[str, Any]) -> None:
|
||||
expected = f'Union[{names}]'
|
||||
raise TypeError(f'Invalid value type for "{key}";'
|
||||
f' expected "{expected}", got'
|
||||
f' "{type(value).__name__}".')
|
||||
f' "{valuetype.__name__}".')
|
||||
|
||||
elif fieldtype in _LIST_ASSIGN_TYPES:
|
||||
reqtypes = _LIST_ASSIGN_TYPES[fieldtype]
|
||||
if not isinstance(value, list):
|
||||
raise TypeError(
|
||||
f'Invalid value for "{key}";'
|
||||
f' expected a list, got a "{type(value).__name__}"')
|
||||
for subvalue in value:
|
||||
subvaluetype = type(subvalue)
|
||||
if not any(subvaluetype is t for t in reqtypes):
|
||||
if len(reqtypes) == 1:
|
||||
expected = reqtypes[0].__name__
|
||||
else:
|
||||
names = ', '.join(t.__name__ for t in reqtypes)
|
||||
expected = f'Union[{names}]'
|
||||
raise TypeError(f'Invalid value type for "{key}";'
|
||||
f' expected list of "{expected}", found'
|
||||
f' "{subvaluetype.__name__}".')
|
||||
|
||||
else:
|
||||
raise TypeError(f'Field type "{fieldtype}" is unsupported here.')
|
||||
|
||||
# Ok, if we made it here, the value is kosher. Do the assign.
|
||||
setattr(instance, key, value)
|
||||
|
||||
|
||||
def dataclass_validate(instance: Any) -> None:
|
||||
"""Ensure values in a dataclass are correct types.
|
||||
|
||||
Note that this will always fail if a dataclass contains field types
|
||||
not supported by this module.
|
||||
"""
|
||||
# We currently simply operate by grabbing dataclass values as a dict
|
||||
# and passing them through dataclass_assign().
|
||||
# It would be possible to write slightly more efficient custom code,
|
||||
# this, but this keeps things simple and will allow us to easily
|
||||
# incorporate things like value coercion later if we add that.
|
||||
dataclass_assign(instance, dataclasses.asdict(instance))
|
||||
|
||||
@ -82,15 +82,19 @@ def formatcode(projroot: Path, full: bool) -> None:
|
||||
|
||||
def cpplint(projroot: Path, full: bool) -> None:
|
||||
"""Run lint-checking on all code deemed lint-able."""
|
||||
# pylint: disable=too-many-locals
|
||||
import tempfile
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from multiprocessing import cpu_count
|
||||
from efrotools import get_config
|
||||
from efro.terminal import Clr
|
||||
from efro.error import CleanError
|
||||
|
||||
os.chdir(projroot)
|
||||
filenames = get_code_filenames(projroot)
|
||||
if any(' ' in name for name in filenames):
|
||||
raise Exception('found space in path; unexpected')
|
||||
for fpath in filenames:
|
||||
if ' ' in fpath:
|
||||
raise Exception(f'Found space in path {fpath}; unexpected.')
|
||||
|
||||
# Check the config for a list of ones to ignore.
|
||||
code_blacklist: List[str] = get_config(projroot).get(
|
||||
@ -114,14 +118,47 @@ def cpplint(projroot: Path, full: bool) -> None:
|
||||
print(f'{Clr.BLU}CppLint checking'
|
||||
f' {len(dirtyfiles)} file(s)...{Clr.RST}')
|
||||
|
||||
def lint_file(filename: str) -> None:
|
||||
result = subprocess.call(['cpplint', '--root=src', filename])
|
||||
if result != 0:
|
||||
raise Exception(f'Linting failed for {filename}')
|
||||
# We want to do a few custom modifications to the cpplint module...
|
||||
try:
|
||||
import cpplint as cpplintmodule
|
||||
except Exception:
|
||||
raise CleanError('Unable to import cpplint')
|
||||
with open(cpplintmodule.__file__) as infile:
|
||||
codelines = infile.read().splitlines()
|
||||
cheadersline = codelines.index('_C_HEADERS = frozenset([')
|
||||
|
||||
with ThreadPoolExecutor(max_workers=cpu_count()) as executor:
|
||||
# Converting this to a list will propagate any errors.
|
||||
list(executor.map(lint_file, dirtyfiles))
|
||||
# Extra headers we consider as valid C system headers.
|
||||
c_headers = [
|
||||
'malloc.h', 'tchar.h', 'jni.h', 'android/log.h', 'EGL/egl.h',
|
||||
'libgen.h', 'linux/netlink.h', 'linux/rtnetlink.h', 'android/bitmap.h',
|
||||
'android/log.h', 'uuid/uuid.h', 'cxxabi.h', 'direct.h', 'shellapi.h',
|
||||
'rpc.h', 'io.h'
|
||||
]
|
||||
codelines.insert(cheadersline + 1, ''.join(f"'{h}'," for h in c_headers))
|
||||
|
||||
# Skip unapproved C++ headers check (it flags <mutex>, <thread>, etc.)
|
||||
headercheckline = codelines.index(
|
||||
" if include and include.group(1) in ('cfenv',")
|
||||
codelines[headercheckline] = (
|
||||
" if False and include and include.group(1) in ('cfenv',")
|
||||
|
||||
def lint_file(filename: str) -> None:
|
||||
result = subprocess.call(['cpplint', '--root=src', filename], env=env)
|
||||
if result != 0:
|
||||
raise CleanError(
|
||||
f'{Clr.RED}Cpplint failed for {filename}.{Clr.RST}')
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
|
||||
# Write our replacement module, make it discoverable, then run.
|
||||
with open(tmpdir + '/cpplint.py', 'w') as outfile:
|
||||
outfile.write('\n'.join(codelines))
|
||||
env = os.environ.copy()
|
||||
env['PYTHONPATH'] = tmpdir
|
||||
|
||||
with ThreadPoolExecutor(max_workers=cpu_count()) as executor:
|
||||
# Converting this to a list will propagate any errors.
|
||||
list(executor.map(lint_file, dirtyfiles))
|
||||
|
||||
if dirtyfiles:
|
||||
cache.mark_clean(filenames)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user