architect-py 5.0.0b3__py3-none-any.whl → 5.1.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.
- architect_py/__init__.py +432 -5
- architect_py/async_client.py +77 -43
- architect_py/client.py +11 -4
- architect_py/client.pyi +504 -0
- architect_py/common_types/__init__.py +2 -1
- architect_py/common_types/time_in_force.py +94 -0
- architect_py/common_types/tradable_product.py +9 -0
- architect_py/graphql_client/__init__.py +1 -216
- architect_py/graphql_client/client.py +2 -1043
- architect_py/graphql_client/enums.py +0 -72
- architect_py/graphql_client/fragments.py +4 -152
- architect_py/grpc/__init__.py +0 -143
- architect_py/grpc/client.py +6 -1
- architect_py/grpc/models/Core/RestartCptyRequest.py +40 -0
- architect_py/grpc/models/Core/RestartCptyResponse.py +20 -0
- architect_py/grpc/models/Marketdata/Liquidation.py +0 -1
- architect_py/grpc/models/Marketdata/Ticker.py +14 -1
- architect_py/grpc/models/Marketdata/TickersRequest.py +38 -12
- architect_py/grpc/models/Marketdata/Trade.py +0 -1
- architect_py/grpc/models/Oms/Order.py +33 -24
- architect_py/grpc/models/Oms/PlaceOrderRequest.py +33 -24
- architect_py/grpc/models/__init__.py +113 -2
- architect_py/grpc/models/definitions.py +2 -32
- architect_py/grpc/utils.py +1 -4
- architect_py/tests/test_order_entry.py +2 -3
- architect_py/tests/test_orderflow.py +1 -1
- architect_py/utils/pandas.py +4 -3
- architect_py-5.1.0.dist-info/METADATA +66 -0
- {architect_py-5.0.0b3.dist-info → architect_py-5.1.0.dist-info}/RECORD +48 -67
- {architect_py-5.0.0b3.dist-info → architect_py-5.1.0.dist-info}/WHEEL +1 -1
- examples/book_subscription.py +1 -2
- examples/candles.py +1 -3
- examples/common.py +1 -2
- examples/external_cpty.py +2 -2
- examples/funding_rate_mean_reversion_algo.py +9 -6
- examples/order_sending.py +29 -9
- examples/stream_l1_marketdata.py +1 -2
- examples/stream_l2_marketdata.py +1 -2
- examples/trades.py +1 -2
- examples/tutorial_async.py +6 -8
- examples/tutorial_sync.py +6 -7
- scripts/add_imports_to_inits.py +146 -0
- scripts/correct_sync_interface.py +143 -0
- scripts/postprocess_grpc.py +57 -11
- scripts/preprocess_grpc_schema.py +2 -0
- scripts/prune_graphql_schema.py +187 -0
- architect_py/client_interface.py +0 -63
- architect_py/common_types/scalars.py +0 -25
- architect_py/graphql_client/cancel_all_orders_mutation.py +0 -17
- architect_py/graphql_client/cancel_order_mutation.py +0 -23
- architect_py/graphql_client/create_jwt.py +0 -17
- architect_py/graphql_client/get_account_history_query.py +0 -27
- architect_py/graphql_client/get_account_query.py +0 -23
- architect_py/graphql_client/get_account_summaries_query.py +0 -27
- architect_py/graphql_client/get_account_summary_query.py +0 -25
- architect_py/graphql_client/get_candle_snapshot_query.py +0 -27
- architect_py/graphql_client/get_fills_query.py +0 -69
- architect_py/graphql_client/get_historical_orders_query.py +0 -27
- architect_py/graphql_client/get_l_1_book_snapshot_query.py +0 -21
- architect_py/graphql_client/get_l_1_book_snapshots_query.py +0 -23
- architect_py/graphql_client/get_l_2_book_snapshot_query.py +0 -25
- architect_py/graphql_client/get_market_status_query.py +0 -25
- architect_py/graphql_client/get_open_orders_query.py +0 -25
- architect_py/graphql_client/list_accounts_query.py +0 -23
- architect_py/graphql_client/place_order_mutation.py +0 -23
- architect_py/graphql_client/subscribe_candles.py +0 -16
- architect_py/graphql_client/subscribe_orderflow.py +0 -100
- architect_py/graphql_client/subscribe_trades.py +0 -27
- architect_py/graphql_client/user_email_query.py +0 -17
- architect_py/internal_utils/__init__.py +0 -0
- architect_py/internal_utils/no_pandas.py +0 -3
- architect_py-5.0.0b3.dist-info/METADATA +0 -123
- scripts/generate_sync_interface.py +0 -226
- {architect_py-5.0.0b3.dist-info → architect_py-5.1.0.dist-info}/licenses/LICENSE +0 -0
- {architect_py-5.0.0b3.dist-info → architect_py-5.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,143 @@
|
|
1
|
+
import argparse
|
2
|
+
import inspect
|
3
|
+
import re
|
4
|
+
import textwrap
|
5
|
+
|
6
|
+
from architect_py import Client
|
7
|
+
|
8
|
+
|
9
|
+
def delete_method_and_docstring(names: list[str], lines: list[str]) -> list[str]:
|
10
|
+
"""
|
11
|
+
Delete a method and its docstring from the lines of a file if the method name
|
12
|
+
contains any of the names in the provided list.
|
13
|
+
"""
|
14
|
+
i = 0
|
15
|
+
delete_flag = False
|
16
|
+
while i < len(lines):
|
17
|
+
line = lines[i]
|
18
|
+
if "def" in line or "@" in line:
|
19
|
+
delete_flag = False
|
20
|
+
|
21
|
+
if delete_flag:
|
22
|
+
del lines[i]
|
23
|
+
else:
|
24
|
+
if "def" in line and (any(word in line for word in names)):
|
25
|
+
delete_flag = True
|
26
|
+
del lines[i]
|
27
|
+
if "@" in lines[i - 1]:
|
28
|
+
del lines[i - 1]
|
29
|
+
i -= 1
|
30
|
+
else:
|
31
|
+
i += 1
|
32
|
+
return lines
|
33
|
+
|
34
|
+
|
35
|
+
def add_correct_docstring_and_correct_the_init(content: str):
|
36
|
+
lines = content.splitlines()
|
37
|
+
|
38
|
+
cls_doc = inspect.getdoc(Client)
|
39
|
+
indented_cls_doc = textwrap.indent(f'"""\n{cls_doc}\n"""', " ")
|
40
|
+
|
41
|
+
init_method = Client.__init__
|
42
|
+
init_sig = inspect.signature(init_method)
|
43
|
+
init_doc = inspect.getdoc(init_method)
|
44
|
+
indented_init_doc = textwrap.indent(f'"""\n{init_doc}\n"""', " " * 8)
|
45
|
+
|
46
|
+
params = list(init_sig.parameters.values())
|
47
|
+
if params and params[0].name == "self":
|
48
|
+
params = params[1:]
|
49
|
+
|
50
|
+
pos_params = [
|
51
|
+
p
|
52
|
+
for p in params
|
53
|
+
if p.kind
|
54
|
+
in (
|
55
|
+
inspect.Parameter.POSITIONAL_ONLY,
|
56
|
+
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
57
|
+
)
|
58
|
+
]
|
59
|
+
kwonly_params = [p for p in params if p.kind is inspect.Parameter.KEYWORD_ONLY]
|
60
|
+
if kwonly_params:
|
61
|
+
param_parts = (
|
62
|
+
[str(p) for p in pos_params] + ["*"] + [str(p) for p in kwonly_params]
|
63
|
+
)
|
64
|
+
else:
|
65
|
+
param_parts = [str(p) for p in pos_params]
|
66
|
+
|
67
|
+
# turn Optional[Type] into Type | None
|
68
|
+
opt_re = re.compile(r"\b(?:Optional|Option)\[([^]]+)]")
|
69
|
+
param_parts = [opt_re.sub(r"\1 | None", s) for s in param_parts]
|
70
|
+
|
71
|
+
param_str = ", ".join(param_parts)
|
72
|
+
|
73
|
+
return_str = (
|
74
|
+
"None"
|
75
|
+
if init_sig.return_annotation is inspect.Signature.empty
|
76
|
+
else init_sig.return_annotation
|
77
|
+
)
|
78
|
+
|
79
|
+
i = 0
|
80
|
+
while i < len(lines):
|
81
|
+
if "class" in lines[i]:
|
82
|
+
lines.insert(i + 1, indented_cls_doc)
|
83
|
+
break
|
84
|
+
i += 1
|
85
|
+
|
86
|
+
i = 0
|
87
|
+
while i < len(lines):
|
88
|
+
if "def __init__" in lines[i]:
|
89
|
+
break
|
90
|
+
i += 1
|
91
|
+
|
92
|
+
delete_method_and_docstring(["__init__"], lines)
|
93
|
+
|
94
|
+
lines.insert(i - 1, indented_init_doc)
|
95
|
+
init_params = f", {param_str}" if param_str else ""
|
96
|
+
lines.insert(i - 1, f" def __init__(self{init_params}) -> {return_str}:")
|
97
|
+
|
98
|
+
return "\n".join(lines)
|
99
|
+
|
100
|
+
|
101
|
+
def correct_sync_interface(content: str):
|
102
|
+
"""
|
103
|
+
Correct the sync interface in the gRPC service definitions.
|
104
|
+
|
105
|
+
These lines are sensitive to the order of the lines in the file.
|
106
|
+
"""
|
107
|
+
|
108
|
+
content = f"# fmt: off\n# mypy: ignore-errors\n# ruff: noqa\n{content}"
|
109
|
+
|
110
|
+
# Remove all stream, orderflow, and subscribe methods
|
111
|
+
lines = content.splitlines()
|
112
|
+
delete_method_and_docstring(["stream", "orderflow", "subscribe", "connect"], lines)
|
113
|
+
content = "\n".join(lines)
|
114
|
+
|
115
|
+
# Replace the async method definitions with sync method definitions
|
116
|
+
content = content.replace("async def", "def")
|
117
|
+
content = content.replace("await ", "")
|
118
|
+
content = content.replace("AsyncClient", "Client")
|
119
|
+
|
120
|
+
return content
|
121
|
+
|
122
|
+
|
123
|
+
def main(content: str) -> str:
|
124
|
+
content = correct_sync_interface(content)
|
125
|
+
content = add_correct_docstring_and_correct_the_init(content)
|
126
|
+
|
127
|
+
return content
|
128
|
+
|
129
|
+
|
130
|
+
if __name__ == "__main__":
|
131
|
+
parser = argparse.ArgumentParser(description="Process gRPC service definitions")
|
132
|
+
parser.add_argument(
|
133
|
+
"--file_path",
|
134
|
+
type=str,
|
135
|
+
help="Path to the async_client.pyi file",
|
136
|
+
)
|
137
|
+
args = parser.parse_args()
|
138
|
+
|
139
|
+
with open(args.file_path, "r") as f:
|
140
|
+
content = f.read()
|
141
|
+
content = main(content)
|
142
|
+
with open(args.file_path, "w") as f:
|
143
|
+
f.write(content)
|
scripts/postprocess_grpc.py
CHANGED
@@ -19,9 +19,6 @@ from typing import Annotated, List, Tuple, Union, get_args, get_origin
|
|
19
19
|
# Regular Expressions (Constants)
|
20
20
|
# --------------------------------------------------------------------
|
21
21
|
|
22
|
-
REMOVE_ORDERDIR_RE = re.compile(
|
23
|
-
r"^class\s+OrderDir\b.*?(?=^class\s+\w|\Z)", re.DOTALL | re.MULTILINE
|
24
|
-
)
|
25
22
|
IMPORT_FIX_RE = re.compile(r"^from\s+(\.+)(\w*)\s+import\s+(.+)$")
|
26
23
|
CLASS_HEADER_RE = re.compile(r"^(\s*)class\s+(\w+)\([^)]*Enum[^)]*\)\s*:")
|
27
24
|
MEMBER_RE = re.compile(r"^(\s*)(\w+)\s*=\s*([0-9]+)(.*)")
|
@@ -304,6 +301,8 @@ def create_tagged_subtypes_for_variant_types(content: str, json_data: dict) -> s
|
|
304
301
|
def fix_lines(content: str) -> str:
|
305
302
|
"""
|
306
303
|
Fixes type annotations and adds necessary imports.
|
304
|
+
|
305
|
+
Replaces OrderDir and TimeInForce with its handrolled versions.
|
307
306
|
"""
|
308
307
|
lines = content.splitlines(keepends=True)
|
309
308
|
|
@@ -312,13 +311,23 @@ def fix_lines(content: str) -> str:
|
|
312
311
|
|
313
312
|
lines = [line.replace("Dir", "OrderDir") for line in lines]
|
314
313
|
lines = [line.replace("definitions.OrderDir", "OrderDir") for line in lines]
|
315
|
-
lines = [line.replace("
|
314
|
+
lines = [line.replace("definitions.TimeInForce", "TimeInForce") for line in lines]
|
315
|
+
|
316
|
+
order_dir_exists = any("OrderDir" in line for line in lines)
|
317
|
+
time_in_force_exists = any("TimeInForce" in line for line in lines)
|
318
|
+
if order_dir_exists:
|
319
|
+
if not time_in_force_exists:
|
320
|
+
lines.insert(4, "from architect_py.common_types import OrderDir\n")
|
321
|
+
else:
|
322
|
+
lines.insert(
|
323
|
+
4, "from architect_py.common_types import OrderDir, TimeInForce\n"
|
324
|
+
)
|
316
325
|
|
317
|
-
|
318
|
-
|
326
|
+
lines = [line.replace("(Struct)", "(Struct, omit_defaults=True)") for line in lines]
|
327
|
+
delete_class(["OrderDir", "TimeInForceEnum", "GoodTilDate"], lines)
|
319
328
|
|
320
329
|
content = "".join(lines)
|
321
|
-
|
330
|
+
|
322
331
|
return content
|
323
332
|
|
324
333
|
|
@@ -355,7 +364,11 @@ def add_post_processing_to_unflattened_types(content: str, json_data: dict) -> s
|
|
355
364
|
conditional = "if" if i == 0 else "elif"
|
356
365
|
title = properties[enum_tag]["title"]
|
357
366
|
req_keys_subset = [key for key in required_keys if key not in common_keys]
|
358
|
-
should_be_empty_keys = list(union_keys - set(required_keys))
|
367
|
+
should_be_empty_keys: list[str] = list(union_keys - set(required_keys))
|
368
|
+
|
369
|
+
req_keys_subset.sort()
|
370
|
+
should_be_empty_keys.sort()
|
371
|
+
|
359
372
|
lines.append(
|
360
373
|
f' {conditional} self.{enum_tag} == "{enum_value}":\n'
|
361
374
|
f" if not all(getattr(self, key) is not None for key in {req_keys_subset}):\n"
|
@@ -459,6 +472,38 @@ def generate_stub(content: str, json_data: dict) -> str:
|
|
459
472
|
return "".join(lines)
|
460
473
|
|
461
474
|
|
475
|
+
def delete_class(names: list[str], lines: list[str]) -> list[str]:
|
476
|
+
"""
|
477
|
+
Delete a method and its docstring from the lines of a file if the method name
|
478
|
+
contains any of the names in the provided list.
|
479
|
+
"""
|
480
|
+
class_keywords = ["class", "Union"]
|
481
|
+
|
482
|
+
i = 0
|
483
|
+
delete_bool = False
|
484
|
+
while i < len(lines):
|
485
|
+
line = lines[i]
|
486
|
+
if any(word in line for word in class_keywords) and "@" not in line:
|
487
|
+
delete_bool = False
|
488
|
+
elif lines[i : i + 2] == ["\n", "\n"]:
|
489
|
+
delete_bool = False
|
490
|
+
|
491
|
+
if delete_bool:
|
492
|
+
del lines[i]
|
493
|
+
else:
|
494
|
+
if any(c in line for c in class_keywords) and (
|
495
|
+
any(word in line for word in names)
|
496
|
+
):
|
497
|
+
delete_bool = True
|
498
|
+
del lines[i]
|
499
|
+
if "@" in lines[i - 1]:
|
500
|
+
i = -1
|
501
|
+
del lines[i]
|
502
|
+
else:
|
503
|
+
i += 1
|
504
|
+
return lines
|
505
|
+
|
506
|
+
|
462
507
|
def fix_enum_member_names(content: str, json_data: dict) -> str:
|
463
508
|
"""
|
464
509
|
Fixes enum member names based on JSON definitions.
|
@@ -575,13 +620,14 @@ def part_1(py_file_path: str, json_data: dict) -> None:
|
|
575
620
|
|
576
621
|
def part_2(py_file_path: str, json_data: dict) -> None:
|
577
622
|
content = read_file(py_file_path)
|
578
|
-
if
|
623
|
+
if py_file_path.endswith("definitions.py"):
|
579
624
|
"""
|
580
625
|
we write and then read the same file because we need to update the content for when we do the import for the variant types
|
581
626
|
"""
|
582
|
-
content = generate_stub(content, json_data)
|
583
|
-
else:
|
584
627
|
content = content.replace(' "SENTINAL_VALUE"', "")
|
628
|
+
content = content.replace("Model = Any", "")
|
629
|
+
else:
|
630
|
+
content = generate_stub(content, json_data)
|
585
631
|
|
586
632
|
write_file(py_file_path, content)
|
587
633
|
|
@@ -389,6 +389,8 @@ def correct_enums_with_descriptions(schema: Dict[str, Any]) -> None:
|
|
389
389
|
|
390
390
|
If a enum value has a description, the json gets separated
|
391
391
|
|
392
|
+
This renames the enum to the description and adds a new enum
|
393
|
+
|
392
394
|
See TimeInForce for an example
|
393
395
|
"""
|
394
396
|
if "definitions" not in schema:
|
@@ -0,0 +1,187 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Strips unused object-types, enums, inputs, interfaces and unions
|
4
|
+
from a GraphQL schema, keeping only what is referenced by the operations
|
5
|
+
in queries.graphql. Any root operation (mutation / subscription) whose
|
6
|
+
type definition is pruned away is also removed from the `schema { … }`
|
7
|
+
block.
|
8
|
+
|
9
|
+
As a part of the update_schema.py, this script is OPTIONAL but a good idea
|
10
|
+
|
11
|
+
Usage:
|
12
|
+
python prune_schema.py full_schema.graphql queries.graphql schema.graphql
|
13
|
+
"""
|
14
|
+
|
15
|
+
import sys
|
16
|
+
from pathlib import Path
|
17
|
+
from typing import Set, cast
|
18
|
+
|
19
|
+
from graphql import (
|
20
|
+
ListTypeNode,
|
21
|
+
NonNullTypeNode,
|
22
|
+
TypeInfo,
|
23
|
+
build_ast_schema,
|
24
|
+
get_named_type,
|
25
|
+
parse,
|
26
|
+
print_ast,
|
27
|
+
visit,
|
28
|
+
)
|
29
|
+
from graphql.language import (
|
30
|
+
DocumentNode,
|
31
|
+
EnumTypeDefinitionNode,
|
32
|
+
InputObjectTypeDefinitionNode,
|
33
|
+
InterfaceTypeDefinitionNode,
|
34
|
+
NamedTypeNode,
|
35
|
+
ObjectTypeDefinitionNode,
|
36
|
+
SchemaDefinitionNode,
|
37
|
+
UnionTypeDefinitionNode,
|
38
|
+
Visitor,
|
39
|
+
)
|
40
|
+
from graphql.utilities import TypeInfoVisitor
|
41
|
+
|
42
|
+
SDL_KINDS_TO_PRUNE = (
|
43
|
+
ObjectTypeDefinitionNode,
|
44
|
+
EnumTypeDefinitionNode,
|
45
|
+
InputObjectTypeDefinitionNode,
|
46
|
+
InterfaceTypeDefinitionNode,
|
47
|
+
UnionTypeDefinitionNode,
|
48
|
+
)
|
49
|
+
|
50
|
+
|
51
|
+
# ───────────────────────── helpers ──────────────────────────
|
52
|
+
def _named(node) -> NamedTypeNode:
|
53
|
+
"""Strip List/NonNull wrappers and return the leaf NamedTypeNode."""
|
54
|
+
while isinstance(node, (ListTypeNode, NonNullTypeNode)):
|
55
|
+
node = node.type
|
56
|
+
return cast(NamedTypeNode, node)
|
57
|
+
|
58
|
+
|
59
|
+
def fix_docstring_indentation(sdl: str) -> str:
|
60
|
+
"""Indent docstring bodies by two spaces so they remain readable."""
|
61
|
+
lines = sdl.splitlines()
|
62
|
+
in_doc = False
|
63
|
+
for i, line in enumerate(lines):
|
64
|
+
if line.startswith('"""'):
|
65
|
+
in_doc = not in_doc
|
66
|
+
elif in_doc:
|
67
|
+
lines[i] = f" {line}"
|
68
|
+
return "\n".join(lines)
|
69
|
+
|
70
|
+
|
71
|
+
# ────────────── reachability (what types are used) ──────────────
|
72
|
+
def _reachable_types(schema_sdl: str, queries_sdl: str) -> Set[str]:
|
73
|
+
schema_ast = parse(schema_sdl)
|
74
|
+
schema = build_ast_schema(schema_ast)
|
75
|
+
|
76
|
+
used: Set[str] = set()
|
77
|
+
tinfo = TypeInfo(schema)
|
78
|
+
|
79
|
+
class _Recorder(Visitor):
|
80
|
+
def enter(self, *_):
|
81
|
+
if typ := tinfo.get_type() or tinfo.get_input_type():
|
82
|
+
used.add(get_named_type(typ).name)
|
83
|
+
if (parent := tinfo.get_parent_type()) is not None:
|
84
|
+
used.add(parent.name)
|
85
|
+
|
86
|
+
visit(parse(queries_sdl), TypeInfoVisitor(tinfo, _Recorder()))
|
87
|
+
|
88
|
+
used.update(
|
89
|
+
x
|
90
|
+
for x in (
|
91
|
+
"Int",
|
92
|
+
"Float",
|
93
|
+
"String",
|
94
|
+
"Boolean",
|
95
|
+
"ID",
|
96
|
+
schema.query_type and schema.query_type.name,
|
97
|
+
schema.mutation_type and schema.mutation_type.name,
|
98
|
+
schema.subscription_type and schema.subscription_type.name,
|
99
|
+
)
|
100
|
+
if x
|
101
|
+
)
|
102
|
+
return used
|
103
|
+
|
104
|
+
|
105
|
+
# ─────────────────────── pruning ──────────────────────────────
|
106
|
+
def _prune_ast(schema_ast: DocumentNode, keep: Set[str]) -> DocumentNode:
|
107
|
+
# Pass 1 – drop defs never referenced
|
108
|
+
schema_ast.definitions = tuple(
|
109
|
+
d
|
110
|
+
for d in schema_ast.definitions
|
111
|
+
if not (isinstance(d, SDL_KINDS_TO_PRUNE) and d.name.value not in keep)
|
112
|
+
)
|
113
|
+
|
114
|
+
# Pass 2 – repeatedly:
|
115
|
+
# • remove fields whose types were pruned
|
116
|
+
# • drop container types left with zero fields
|
117
|
+
changed = True
|
118
|
+
while changed:
|
119
|
+
changed = False
|
120
|
+
|
121
|
+
new_defs = []
|
122
|
+
for d in schema_ast.definitions:
|
123
|
+
if isinstance(d, ObjectTypeDefinitionNode):
|
124
|
+
kept_fields = tuple(
|
125
|
+
f for f in (d.fields or []) if _named(f.type).name.value in keep
|
126
|
+
)
|
127
|
+
if len(kept_fields) != len(d.fields or ()):
|
128
|
+
changed = True
|
129
|
+
if kept_fields:
|
130
|
+
new_defs.append(
|
131
|
+
d.__class__( # recreate node with surviving fields
|
132
|
+
name=d.name,
|
133
|
+
interfaces=d.interfaces,
|
134
|
+
directives=d.directives,
|
135
|
+
fields=kept_fields,
|
136
|
+
description=getattr(d, "description", None),
|
137
|
+
loc=d.loc,
|
138
|
+
)
|
139
|
+
)
|
140
|
+
else:
|
141
|
+
changed = True # container emptied → drop it
|
142
|
+
else:
|
143
|
+
new_defs.append(d)
|
144
|
+
schema_ast.definitions = tuple(new_defs)
|
145
|
+
|
146
|
+
# Pass 3 – trim mutation/subscription in the schema block
|
147
|
+
live_names = {
|
148
|
+
d.name.value
|
149
|
+
for d in schema_ast.definitions
|
150
|
+
if isinstance(d, SDL_KINDS_TO_PRUNE)
|
151
|
+
}
|
152
|
+
for defn in schema_ast.definitions:
|
153
|
+
if isinstance(defn, SchemaDefinitionNode):
|
154
|
+
defn.operation_types = tuple(
|
155
|
+
op
|
156
|
+
for op in defn.operation_types
|
157
|
+
if op.operation == "query" or op.type.name.value in live_names
|
158
|
+
)
|
159
|
+
|
160
|
+
return schema_ast
|
161
|
+
|
162
|
+
|
163
|
+
# ─────────────────────── main entry-point ─────────────────────
|
164
|
+
def main(schema_path: str, queries_path: str, out_path: str | None = None) -> None:
|
165
|
+
schema_src = Path(schema_path).read_text()
|
166
|
+
query_src = Path(queries_path).read_text()
|
167
|
+
|
168
|
+
keep = _reachable_types(schema_src, query_src)
|
169
|
+
pruned_ast = _prune_ast(parse(schema_src), keep)
|
170
|
+
|
171
|
+
sdl_out = "\n\n".join(print_ast(defn).strip() for defn in pruned_ast.definitions)
|
172
|
+
sdl_out = fix_docstring_indentation(sdl_out)
|
173
|
+
|
174
|
+
if out_path:
|
175
|
+
Path(out_path).write_text(sdl_out)
|
176
|
+
else:
|
177
|
+
print(sdl_out)
|
178
|
+
|
179
|
+
|
180
|
+
if __name__ == "__main__":
|
181
|
+
if len(sys.argv) < 3:
|
182
|
+
sys.stderr.write(
|
183
|
+
"USAGE: uv run prune_schema.py schema.graphql queries.graphql "
|
184
|
+
"[pruned_schema.graphql]\n"
|
185
|
+
)
|
186
|
+
sys.exit(1)
|
187
|
+
main(sys.argv[1], sys.argv[2], sys.argv[3] if len(sys.argv) > 3 else None)
|
architect_py/client_interface.py
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
# fmt: off
|
2
|
-
|
3
|
-
# mypy: ignore-errors
|
4
|
-
|
5
|
-
# Autogenerated from generate_sync_interface.py
|
6
|
-
|
7
|
-
# If you are here for function definitions, please refer to architect_py/async_client.py
|
8
|
-
# This file is so that the sync client has good type hinting
|
9
|
-
# It is not used for anything else
|
10
|
-
# For maintainers: ensure that the types in this file are correct for correct type hinting
|
11
|
-
|
12
|
-
|
13
|
-
from typing import Any, Union
|
14
|
-
from .graphql_client import *
|
15
|
-
from .async_client import *
|
16
|
-
from .grpc.models.definitions import *
|
17
|
-
class ClientProtocol:
|
18
|
-
def cancel_all_orders(self, account: Optional[str] = None, execution_venue: Optional[str] = None, trader: Optional[str] = None) -> bool: ...
|
19
|
-
def cancel_order(self, order_id: str) -> Cancel: ...
|
20
|
-
def core(self) -> GrpcClient: ...
|
21
|
-
def discover_marketdata(self) -> Any: ...
|
22
|
-
def enable_orderflow(self) -> Any: ...
|
23
|
-
def get_account_history(self, account: str, from_inclusive: Optional[datetime] = None, to_exclusive: Optional[datetime] = None) -> list[AccountSummary]: ...
|
24
|
-
def get_account_summaries(self, accounts: Optional[list[str]] = None, trader: Optional[str] = None) -> list[AccountSummary]: ...
|
25
|
-
def get_account_summary(self, account: str) -> AccountSummary: ...
|
26
|
-
def get_all_open_orders(self) -> list[Order]: ...
|
27
|
-
def get_cme_first_notice_date(self, symbol: str) -> Optional[date]: ...
|
28
|
-
def get_cme_future_from_root_month_year(self, root: str, month: int, year: int) -> str: ...
|
29
|
-
def get_cme_futures_series(self, series: str) -> list[tuple[date, str]]: ...
|
30
|
-
def get_execution_info(self, symbol: Union[TradableProduct, str], execution_venue: str) -> Optional[ExecutionInfoFields]: ...
|
31
|
-
def get_execution_infos(self, symbols: Optional[list[TradableProduct]], execution_venue: Optional[str] = None) -> Sequence[ExecutionInfoFields]: ...
|
32
|
-
@staticmethod
|
33
|
-
def get_expiration_from_CME_name(name: str) -> Optional[date]: ...
|
34
|
-
def get_fills(self, from_inclusive: Optional[datetime] = None, to_exclusive: Optional[datetime] = None, venue: Optional[str] = None, account: Optional[str] = None, order_id: Optional[str] = None, limit: Optional[int] = None) -> HistoricalFillsResponse: ...
|
35
|
-
def get_future_series(self, series_symbol: str) -> list[str]: ...
|
36
|
-
def get_futures_series(self, series_symbol: str) -> list[str]: ...
|
37
|
-
def get_historical_candles(self, symbol: Union[TradableProduct, str], venue: str, candle_width: CandleWidth, start: datetime, end: datetime, *, as_dataframe: bool = False) -> Union[list[Candle], pd.DataFrame]: ...
|
38
|
-
def get_historical_orders(self, order_ids: Optional[list[str]] = None, from_inclusive: Optional[datetime] = None, to_exclusive: Optional[datetime] = None, venue: Optional[str] = None, account: Optional[str] = None, parent_order_id: Optional[str] = None) -> list[Order]: ...
|
39
|
-
def get_l1_book_snapshot(self, symbol: Union[TradableProduct, str], venue: str) -> L1BookSnapshot: ...
|
40
|
-
def get_l1_book_snapshots(self, symbols: list[Union[TradableProduct, str]], venue: str) -> Sequence[L1BookSnapshot]: ...
|
41
|
-
def get_l2_book_snapshot(self, symbol: Union[TradableProduct, str], venue: str) -> L2BookSnapshot: ...
|
42
|
-
def get_market_snapshot(self, symbol: Union[TradableProduct, str], venue: str) -> L1BookSnapshot: ...
|
43
|
-
def get_market_snapshots(self, symbols: list[Union[TradableProduct, str]], venue: str) -> Sequence[L1BookSnapshot]: ...
|
44
|
-
def get_market_status(self, symbol: Union[TradableProduct, str], venue: str) -> MarketStatus: ...
|
45
|
-
def get_open_orders(self, order_ids: Optional[list[str]] = None, venue: Optional[str] = None, account: Optional[str] = None, trader: Optional[str] = None, symbol: Optional[str] = None, parent_order_id: Optional[str] = None) -> list[Order]: ...
|
46
|
-
def get_order(self, order_id: str) -> Optional[Order]: ...
|
47
|
-
def get_orders(self, order_ids: list[str]) -> list[Optional[Order]]: ...
|
48
|
-
def get_product_info(self, symbol: str) -> Optional[ProductInfoFields]: ...
|
49
|
-
def get_product_infos(self, symbols: Optional[list[str]]) -> Sequence[ProductInfoFields]: ...
|
50
|
-
def get_ticker(self, symbol: Union[TradableProduct, str], venue: str) -> Ticker: ...
|
51
|
-
def hmart(self) -> GrpcClient: ...
|
52
|
-
def list_accounts(self) -> list[AccountWithPermissions]: ...
|
53
|
-
def list_symbols(self, *, marketdata: Optional[str] = None) -> list[str]: ...
|
54
|
-
def marketdata(self, venue: str) -> GrpcClient: ...
|
55
|
-
def place_limit_order(self, *, id: Optional[str] = None, symbol: Union[TradableProduct, str], execution_venue: Optional[str] = None, dir: Optional[OrderDir] = None, quantity: Decimal, limit_price: Decimal, order_type: OrderType = OrderType.LIMIT, time_in_force: Union[GoodTilDate, TimeInForceEnum] = TimeInForceEnum.DAY, price_round_method: Optional[TickRoundMethod] = None, account: Optional[str] = None, trader: Optional[str] = None, post_only: bool = False, trigger_price: Optional[Decimal] = None, **kwargs: Any) -> Order: ...
|
56
|
-
def refresh_jwt(self, force: bool = False) -> Any: ...
|
57
|
-
def search_symbols(self, search_string: Optional[str] = None, execution_venue: Optional[str] = None, offset: int = 0, limit: int = 20) -> list[TradableProduct]: ...
|
58
|
-
def send_limit_order(self, *args: Any, **kwargs: Any) -> Order: ...
|
59
|
-
def send_market_pro_order(self, *, id: Optional[str] = None, symbol: Union[TradableProduct, str], execution_venue: str, odir: OrderDir, quantity: Decimal, time_in_force: Union[GoodTilDate, TimeInForceEnum] = TimeInForceEnum.DAY, account: Optional[str] = None, fraction_through_market: Decimal = Decimal('0.001')) -> Order: ...
|
60
|
-
def set_hmart(self, endpoint: str) -> Any: ...
|
61
|
-
def set_jwt(self, jwt: Optional[str], jwt_expiration: Optional[datetime] = None) -> Any: ...
|
62
|
-
def set_marketdata(self, venue: str, endpoint: str) -> Any: ...
|
63
|
-
def who_am_i(self) -> tuple[str, str]: ...
|
@@ -1,25 +0,0 @@
|
|
1
|
-
from datetime import datetime, timezone
|
2
|
-
from typing import TYPE_CHECKING, Optional
|
3
|
-
|
4
|
-
if TYPE_CHECKING:
|
5
|
-
from architect_py.graphql_client.base_model import UnsetType
|
6
|
-
|
7
|
-
|
8
|
-
def convert_datetime_to_utc_str(dt: "Optional[datetime] | UnsetType") -> Optional[str]:
|
9
|
-
if not isinstance(dt, datetime):
|
10
|
-
return None
|
11
|
-
|
12
|
-
if dt.tzinfo is None:
|
13
|
-
raise ValueError(
|
14
|
-
"in a datetime sent to the backend, the good_til_date must be timezone-aware. Try \n"
|
15
|
-
"from zoneinfo import ZoneInfo\n"
|
16
|
-
"datetime(..., tzinfo={your_local_timezone}) or "
|
17
|
-
"datetime.now(tz=ZoneInfo('UTC'))\n"
|
18
|
-
"# examples of local timezones:\n"
|
19
|
-
"ZoneInfo('America/New_York'), "
|
20
|
-
"ZoneInfo('America/Los_Angeles'), ZoneInfo('America/Chicago')"
|
21
|
-
)
|
22
|
-
utc_str = dt.astimezone(timezone.utc).isoformat()[:-6]
|
23
|
-
# [:-6] removes the utc offset
|
24
|
-
|
25
|
-
return f"{utc_str}Z"
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# Generated by ariadne-codegen
|
2
|
-
# Source: queries.graphql
|
3
|
-
|
4
|
-
from pydantic import Field
|
5
|
-
|
6
|
-
from .base_model import BaseModel
|
7
|
-
|
8
|
-
|
9
|
-
class CancelAllOrdersMutation(BaseModel):
|
10
|
-
oms: "CancelAllOrdersMutationOms"
|
11
|
-
|
12
|
-
|
13
|
-
class CancelAllOrdersMutationOms(BaseModel):
|
14
|
-
cancel_all_orders: bool = Field(alias="cancelAllOrders")
|
15
|
-
|
16
|
-
|
17
|
-
CancelAllOrdersMutation.model_rebuild()
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# Generated by ariadne-codegen
|
2
|
-
# Source: queries.graphql
|
3
|
-
|
4
|
-
from pydantic import Field
|
5
|
-
|
6
|
-
from .base_model import BaseModel
|
7
|
-
from .fragments import CancelFields
|
8
|
-
|
9
|
-
|
10
|
-
class CancelOrderMutation(BaseModel):
|
11
|
-
oms: "CancelOrderMutationOms"
|
12
|
-
|
13
|
-
|
14
|
-
class CancelOrderMutationOms(BaseModel):
|
15
|
-
cancel_order: "CancelOrderMutationOmsCancelOrder" = Field(alias="cancelOrder")
|
16
|
-
|
17
|
-
|
18
|
-
class CancelOrderMutationOmsCancelOrder(CancelFields):
|
19
|
-
pass
|
20
|
-
|
21
|
-
|
22
|
-
CancelOrderMutation.model_rebuild()
|
23
|
-
CancelOrderMutationOms.model_rebuild()
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# Generated by ariadne-codegen
|
2
|
-
# Source: queries.graphql
|
3
|
-
|
4
|
-
from pydantic import Field
|
5
|
-
|
6
|
-
from .base_model import BaseModel
|
7
|
-
|
8
|
-
|
9
|
-
class CreateJwt(BaseModel):
|
10
|
-
user: "CreateJwtUser"
|
11
|
-
|
12
|
-
|
13
|
-
class CreateJwtUser(BaseModel):
|
14
|
-
create_jwt: str = Field(alias="createJwt")
|
15
|
-
|
16
|
-
|
17
|
-
CreateJwt.model_rebuild()
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# Generated by ariadne-codegen
|
2
|
-
# Source: queries.graphql
|
3
|
-
|
4
|
-
from typing import List
|
5
|
-
|
6
|
-
from pydantic import Field
|
7
|
-
|
8
|
-
from .base_model import BaseModel
|
9
|
-
from .fragments import AccountSummaryFields
|
10
|
-
|
11
|
-
|
12
|
-
class GetAccountHistoryQuery(BaseModel):
|
13
|
-
folio: "GetAccountHistoryQueryFolio"
|
14
|
-
|
15
|
-
|
16
|
-
class GetAccountHistoryQueryFolio(BaseModel):
|
17
|
-
account_history: List["GetAccountHistoryQueryFolioAccountHistory"] = Field(
|
18
|
-
alias="accountHistory"
|
19
|
-
)
|
20
|
-
|
21
|
-
|
22
|
-
class GetAccountHistoryQueryFolioAccountHistory(AccountSummaryFields):
|
23
|
-
pass
|
24
|
-
|
25
|
-
|
26
|
-
GetAccountHistoryQuery.model_rebuild()
|
27
|
-
GetAccountHistoryQueryFolio.model_rebuild()
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# Generated by ariadne-codegen
|
2
|
-
# Source: queries.graphql
|
3
|
-
|
4
|
-
from typing import Optional
|
5
|
-
|
6
|
-
from .base_model import BaseModel
|
7
|
-
from .fragments import AccountWithPermissionsFields
|
8
|
-
|
9
|
-
|
10
|
-
class GetAccountQuery(BaseModel):
|
11
|
-
user: "GetAccountQueryUser"
|
12
|
-
|
13
|
-
|
14
|
-
class GetAccountQueryUser(BaseModel):
|
15
|
-
account: Optional["GetAccountQueryUserAccount"]
|
16
|
-
|
17
|
-
|
18
|
-
class GetAccountQueryUserAccount(AccountWithPermissionsFields):
|
19
|
-
pass
|
20
|
-
|
21
|
-
|
22
|
-
GetAccountQuery.model_rebuild()
|
23
|
-
GetAccountQueryUser.model_rebuild()
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# Generated by ariadne-codegen
|
2
|
-
# Source: queries.graphql
|
3
|
-
|
4
|
-
from typing import List
|
5
|
-
|
6
|
-
from pydantic import Field
|
7
|
-
|
8
|
-
from .base_model import BaseModel
|
9
|
-
from .fragments import AccountSummaryFields
|
10
|
-
|
11
|
-
|
12
|
-
class GetAccountSummariesQuery(BaseModel):
|
13
|
-
folio: "GetAccountSummariesQueryFolio"
|
14
|
-
|
15
|
-
|
16
|
-
class GetAccountSummariesQueryFolio(BaseModel):
|
17
|
-
account_summaries: List["GetAccountSummariesQueryFolioAccountSummaries"] = Field(
|
18
|
-
alias="accountSummaries"
|
19
|
-
)
|
20
|
-
|
21
|
-
|
22
|
-
class GetAccountSummariesQueryFolioAccountSummaries(AccountSummaryFields):
|
23
|
-
pass
|
24
|
-
|
25
|
-
|
26
|
-
GetAccountSummariesQuery.model_rebuild()
|
27
|
-
GetAccountSummariesQueryFolio.model_rebuild()
|