Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start organizing examples, increase test coverage of examples #174

Merged
merged 3 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ lint-cpp:
echo "C++ linting disabled for now"

lint-docs:
python -m mdformat --check docs/wiki/ README.md examples/README.md
python -m codespell_lib docs/wiki/ README.md examples/README.md
python -m mdformat --check docs/wiki/ README.md examples/
python -m codespell_lib docs/wiki/ README.md examples/ --skip "*.cpp,*.h"

# lint: lint-py lint-cpp ## run lints
lint: lint-py lint-docs ## run lints
Expand All @@ -62,8 +62,8 @@ fix-cpp:
echo "C++ autoformatting disabled for now"

fix-docs:
python -m mdformat docs/wiki/ README.md examples/README.md
python -m codespell_lib --write docs/wiki/ README.md examples/README.md
python -m mdformat docs/wiki/ README.md examples/
python -m codespell_lib --write docs/wiki/ README.md examples/ --skip "*.cpp,*.h"

fix: fix-py fix-cpp fix-docs ## run autofixers

Expand Down
11 changes: 8 additions & 3 deletions conda/dev-environment-unix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,38 @@ channels:
dependencies:
- bison
- brotli
- build
- bump2version>=1
- cmake
- codespell
- compilers
- cyrus-sasl
- exprtk
- flex
- graphviz
- python-graphviz
- gtest
- httpx
- isort
- httpx>=0.20,<1
- isort>=5,<6
- libarrow=15
- librdkafka
- lz4-c
- mamba
- mdformat
- ninja
- numpy
- pillow
- psutil
- pyarrow=15
- pandas
- pillow
- polars
- psutil
- pytz
- pytest
- pytest-asyncio
- pytest-cov
- pytest-sugar
- pytest-asyncio
- python<3.12
- python-rapidjson
- rapidjson
Expand All @@ -43,6 +47,7 @@ dependencies:
- slack-sdk
- sqlalchemy
- tar
- threadpoolctl
- tornado
- twine
- unzip
Expand Down
34 changes: 30 additions & 4 deletions csp/tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ def _get_module(folder, filename):
return None


def _get_modules_to_test(folder):
def _get_modules_to_test(*folders):
folder = ".".join(folders) if len(folders) > 0 else folders[0]
return [
(file, _get_module(folder, file))
for file in os.listdir(os.path.join(EXAMPLES_ROOT, folder))
for file in os.listdir(os.path.join(EXAMPLES_ROOT, *folders))
if file.endswith(".py")
]

Expand All @@ -31,12 +32,37 @@ def _no_examples_folder_or_running_sdist_tests():

@pytest.mark.skipif(_no_examples_folder_or_running_sdist_tests(), reason="no examples present or manually skipping")
class TestExamples:
@pytest.mark.parametrize("filename,module", _get_modules_to_test("1_basics"))
@pytest.mark.parametrize("filename,module", _get_modules_to_test("01_basics"))
def test_1_basics(self, filename, module):
assert module.main
module.main()

@pytest.mark.parametrize("filename,module", _get_modules_to_test("2_intermediate"))
@pytest.mark.parametrize("filename,module", _get_modules_to_test("02_intermediate"))
def test_2_intermediate(self, filename, module):
assert module.main
module.main()

@pytest.mark.parametrize("filename,module", _get_modules_to_test("03_using_adapters", "parquet"))
def test_3_adapters_parquet(self, filename, module):
assert module.main
module.main()

@pytest.mark.parametrize("filename,module", _get_modules_to_test("04_writing_adapters"))
def test_4_writing_adapters(self, filename, module):
assert module.main
module.main()

@pytest.mark.parametrize("filename,module", _get_modules_to_test("06_advanced"))
def test_6_advanced(self, filename, module):
assert module.main
module.main()

@pytest.mark.parametrize("filename,module", _get_modules_to_test("98_just_for_fun"))
def test_98_just_for_fun(self, filename, module):
assert module.main
module.main()

@pytest.mark.parametrize("filename,module", _get_modules_to_test("99_developer_tools"))
def test_99_developer_tools(self, filename, module):
assert module.main
module.main()
6 changes: 6 additions & 0 deletions examples/01_basics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Basics

- [Simplest Possible Graph](./e1_basic.py)
- [Ticking Graphs](./e2_ticking.py)
- [Complete Example (Trading)](./e3_trade_pnl.py)
- [Visualizing a Graph](./e4_show_graph.py)
29 changes: 29 additions & 0 deletions examples/01_basics/e1_basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from datetime import datetime

import csp
from csp import ts


@csp.node
def add(x: ts[int], y: ts[int]) -> ts[int]:
return x + y


@csp.graph
def my_graph():
x = csp.const(1)
y = csp.const(2)

sum = add(x, y)

csp.print("x", x)
csp.print("y", y)
csp.print("sum", sum)


def main():
csp.run(my_graph, starttime=datetime.now())


if __name__ == "__main__":
main()
49 changes: 49 additions & 0 deletions examples/01_basics/e2_ticking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from datetime import datetime, timedelta

import csp
from csp import ts


@csp.node
def add(x: ts[int], y: ts[int]) -> ts[int]:
return x + y


@csp.node
def accum(val: ts[int]) -> ts[int]:
with csp.state():
s_sum = 0
if csp.ticked(val):
s_sum += val
return val


@csp.graph
def my_graph():
st = datetime(2020, 1, 1)

# Dummy x values
x = csp.curve(int, [(st + timedelta(1), 1), (st + timedelta(2), 2), (st + timedelta(3), 3)])

# Dummy y values
y = csp.curve(int, [(st + timedelta(1), -1), (st + timedelta(3), -1), (st + timedelta(4), -1)])

# Add the time series
sum = add(x, y)

# Accumulate the result
acc = accum(sum)

csp.print("x", x)
csp.print("y", y)
csp.print("sum", sum)
csp.print("accum", acc)


def main():
start = datetime(2020, 1, 1)
csp.run(my_graph, starttime=start)


if __name__ == "__main__":
main()
6 changes: 6 additions & 0 deletions examples/02_intermediate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Intermediate

- [Graph Loops (`csp.feedback`)](./e1_feedback.py)
- [Statistics Nodes](./e2_stats.py)
- [Statistics Nodes with Numpy](./e3_numpy_stats.py)
- [Expression Nodes with `exprtk`](./e4_exprtk.py)
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def main():
if show_graph:
csp.showgraph.show_graph(my_graph)
else:
csp.run(my_graph, starttime=datetime.utcnow(), endtime=timedelta(seconds=60), realtime=True)
csp.run(my_graph, starttime=datetime.utcnow(), endtime=timedelta(seconds=5), realtime=False)


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def numpy_stats_graph():


def main():
results = csp.run(numpy_stats_graph, starttime=st, endtime=st + timedelta(minutes=10))
results = csp.run(numpy_stats_graph, starttime=st, endtime=st + timedelta(minutes=10), realtime=False)

print("Price Averages\n")
for i in range(10):
Expand Down
3 changes: 3 additions & 0 deletions examples/03_using_adapters/kafka/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Kafka Adapter

- [Kafka Example](./e1_kafka.py)
3 changes: 3 additions & 0 deletions examples/03_using_adapters/parquet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Parquet Adapter

- [Parquet Writer](./e1_parquet_writer.py)
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ def my_graph(struct_file_name: str, series_file_name: str):
write_series(series_file_name)


if __name__ == "__main__":
def main():
with tempfile.NamedTemporaryFile(suffix=".parquet") as struct_file:
struct_file.file.close()
with tempfile.NamedTemporaryFile(suffix=".parquet") as series_file:
series_file.file.close()
g = csp.run(
csp.run(
my_graph,
struct_file.name,
series_file.name,
Expand All @@ -72,3 +72,7 @@ def my_graph(struct_file_name: str, series_file_name: str):
print(f"Struct data:\n{struct_df}")
series_df = pandas.read_parquet(series_file.name)
print(f"Series data:\n{series_df}")


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions examples/03_using_adapters/slack/README.me
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Slack Adapter
3 changes: 3 additions & 0 deletions examples/03_using_adapters/websocket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Websocket Adapter

- [Websocket Output](./e1_websocket_output.py)
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def times(timer: ts[bool]) -> ts[datetime]:


@csp.graph
def main(port: int, num_keys: int):
def my_graph(port: int, num_keys: int):
snap = csp.timer(timedelta(seconds=0.25))
angle = csp.count(snap)

Expand Down Expand Up @@ -57,7 +57,10 @@ def main(port: int, num_keys: int):
port = 7677
num_keys = 10

csp.run(main, port, num_keys, starttime=datetime.utcnow(), endtime=timedelta(seconds=360), realtime=True)

def main():
csp.run(my_graph, port, num_keys, starttime=datetime.utcnow(), endtime=timedelta(seconds=360), realtime=True)


""" Sample html to view the data. Note to put your machine name on the websocket line below
<html>
Expand All @@ -84,3 +87,6 @@ def main(port: int, num_keys: int):
</body>
</html>
"""

if __name__ == "__main__":
main()
9 changes: 9 additions & 0 deletions examples/04_writing_adapters/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Writing Adapters

- [Generic Push Adapter](./e1_generic_push_adapter.py)
- [Pull Input Adapter](./e2_pullinput.py)
- [Pull Input Adapter with Adapter Manager](./e3_adaptermanager_pullinput.py)
- [Push Input Adapter](./e4_pushinput.py)
- [Push Input Adapter with Adapter Manager](./e5_adaptermanager_pushinput.py)
- [Output Adapter](./e6_outputadapter.py)
- [Complete Input/Output Adapter with Adapter Manager](./e7_adaptermanager_inputoutput.py)
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def _run(self):
counter = 0
# Optionally, we can wait for the adapter to start before proceeding
# Alternatively we can start pushing data, but push_tick may fail and return False if
# the csp engine isnt ready yet
# the csp engine isn't ready yet
self._adapter.wait_for_start()

while self._active and not self._adapter.stopped():
Expand All @@ -52,4 +52,9 @@ def my_graph():
csp.print("data", adapter.out())


csp.run(my_graph, realtime=True, starttime=datetime.utcnow(), endtime=timedelta(seconds=10))
def main():
csp.run(my_graph, realtime=True, starttime=datetime.utcnow(), endtime=timedelta(seconds=2))


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
PullInputAdapter is the simplest form of an input adapter for historical data. One instance is created
to provide data on a single timeseries. There are use cases for this construct, though they are limited.
This is useful when feeding a single source of historical data into a single timeseries. In most cases however,
you will likely have a single source that is processed and used to provide data to multiple inputs. For that construct
see e_14_user_adapters_02_adaptermanager_siminput.py
PullInputAdapter is the simplest form of an input adapter for historical data. One instance is created
to provide data on a single timeseries. There are use cases for this construct, though they are limited.
This is useful when feeding a single source of historical data into a single timeseries. In most cases however,
you will likely have a single source that is processed and used to provide data to multiple inputs. For that construct
see e3_adaptermanager_pullinput.py
"""

from datetime import datetime, timedelta
Expand Down Expand Up @@ -45,7 +45,7 @@ def next(self):
return None


# MyPullAdapter is the graph-building time construct. This is simply a representation of what the
# MyPullAdapter is the graph-building time construct. This is simply a representation of what the
# input adapter is and how to create it, including the Impl to use and arguments to pass into it upon construction
MyPullAdapter = py_pull_adapter_def("MyPullAdapter", MyPullAdapterImpl, ts[int], interval=timedelta, num_ticks=int)

Expand All @@ -58,4 +58,9 @@ def my_graph():
print("End of graph building")


csp.run(my_graph, starttime=datetime(2020, 12, 28))
def main():
csp.run(my_graph, starttime=datetime(2020, 12, 28))


if __name__ == "__main__":
main()
Loading