Skip to content

test: cover the client content panes, mark the suite, and report coverage in CI (PyTest - 10) - #1692

Open
Manik-Khajuria-5 wants to merge 52 commits into
fossasia:devfrom
Manik-Khajuria-5:Testing-10
Open

test: cover the client content panes, mark the suite, and report coverage in CI (PyTest - 10)#1692
Manik-Khajuria-5 wants to merge 52 commits into
fossasia:devfrom
Manik-Khajuria-5:Testing-10

Conversation

@Manik-Khajuria-5

@Manik-Khajuria-5 Manik-Khajuria-5 commented Aug 6, 2026

Copy link
Copy Markdown
Member

Description

Adds py/tests/unit/client_content.py, covering text, properties, table, learning_curve, update_window_opts, embeddings and the window/env calls against an offline client. do_tsne is patched so there's no t-SNE dependency.

Two fixes the tests turned up:

  • get_env_list() was asking for a single env. _send fills in a missing eid with the client's env, so /env_state handed back that env's windows instead of the env names. Added default_eid to _send and passed default_eid=False here.

  • The experiment-log tests were waiting on a socket that never opened. Moved them onto VisdomHTTPTestCase that file went from 37.99s to 0.17s.

Fixes : #1695

Motivation and Context

There was no way to run just the cheap tests, and 38 seconds of the suite was one file waiting on a socket. Both source changes are real bugs, not cleanups get_env_list() returning the wrong shape is user-facing.

How Has This Been Tested?

Python 3.12:

$ pytest -m "not server" --cov=visdom

$ pytest -m unit
1075 passed, 430 deselected in 1.99s

The skip is build_verification.py, which needs the frontend deps

Screenshots (if appropriate):

n/a

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code refactor or cleanup (changes to existing code for improv)

Checklist:

  • I adapted the version number under py/visdom/VERSION according to Semantic Versioning
  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

Summary by Sourcery

Add extensive unit and integration coverage for client content panes, server handlers, storage durability, and socket commands, while tightening readonly enforcement, improving error handling and security, and wiring a fast unit-test gate with coverage reporting in CI.

Bug Fixes:

  • Ensure get_env_list() talks to /env_state without defaulting to the client env so it returns the environment list rather than a single env's windows.
  • Make JSONStore environment saves atomic via temporary files and os.replace, align undo saves to the same helper, and avoid treating stranded staging files as real environments.
  • Fix socket close handling so panes are only popped once per escaped eid and layout updates broadcast correctly to all subscribers and polling clients.
  • Enforce readonly mode consistently across HTTP handlers and socket paths, including win_data uploads and mixed read/write routes.
  • Guard embeddings pop operations against empty history, handle malformed frame indices in plot history updates, and prevent IndexError/TypeError from escaping the socket loop.
  • Use constant-time comparison for login credentials, stop leaking stack traces and raw requests in production error pages, and avoid crashes on malformed compare_envs inputs or bad client payloads.
  • Cap image, text, embeddings, and plot histories in memory to prevent unbounded growth during long-running jobs.
  • Fix images() grid placement and padding calculations so zero-padding configurations no longer raise and tiles stay centered.
  • Handle categorical axes and all-missing numeric updates safely in plot updates, and ensure named trace updates validate their payload size.

Enhancements:

  • Add max_plot_history default and thread it through Application and UpdateHandler to bound plot history panes.
  • Extend UpdateHandler’s plot update logic to support deletion flags, enforce one-entry named updates, and skip updates made entirely of missing values using a shared _is_missing_value helper.
  • Refine compare_envs to skip unnamed or malformed plots, handle empty content safely, and preserve legends and layouts while avoiding collisions between window indices.
  • Refactor server utils and handlers to use shared readonly helpers, improved index assignment for new windows, and safer env comparisons.
  • Document the testing strategy, markers, and CI layout in .agents/context/testing.md and AGENTS.md, including how unit vs integration markers must cover the entire suite.
  • Exclude test packages from the distribution in setup.py and ensure pythonpath/test discovery configuration keeps helper modules importable but uncollected.

CI:

  • Split python-tests workflow into a fast unit gate (pytest -m unit on 3.12) and a full pytest matrix job that runs -m 'not server' with coverage reporting.
  • Configure pytest in pyproject.toml to treat all .py files under py/tests as tests, add pythonpath entries for py and py/tests, exclude testutils from discovery, and register unit/integration/slow/server markers.

Tests:

  • Introduce a structured unit/integration test layout with markers, shared fixtures, and HTTP helpers, and move existing tests into py/tests/unit and py/tests/integration.
  • Add new unit suites for client payloads (media, graph, metrics, helpers), environment comparison, memory caps, t-SNE helpers, run_server CLI, shared_utils, data_model durability, and window building.
  • Add new integration suites exercising HTTP handlers for window/env lifecycle, env transfer, socket commands and lifecycle, update handlers for plots/text/media, authentication/login, polling parity, and build verification.

Adds conftest.py, a testutils package, and unit tests for window().
AsyncHTTPTestCase is a unittest.TestCase, and pytest will not inject
fixtures into those. Run the Application on a background event loop
instead and talk to it with requests, which is already a runtime
dependency, so HTTP tests can be plain functions.
Lands the window lifecycle file as plain pytest functions on the
visdom_server fixture, dropping the per-file setUp block and the
temp directory it never cleaned up.
Collapses the repeated plot-trace and opts assertions into parametrized
tables, so each case reports separately instead of hiding behind the
first failure.
The reload case now builds its second Application from the app_factory
fixture, which shares env_path with visdom_server, instead of hand-rolling
one against a leaked temp directory.
The update-into-a-missing-env case asserted 'status is 200 or 500',
which could not fail. It now pins the actual behaviour: 200 with
'win does not exist'.
register_window took the index from len(env), so closing any window but
the last produced a duplicate index and the pane order went undefined
after a reload. Use max(i) + 1, which is what the undo path already does.
Three validation checks used a bare assert, so an invalid request came
back as a 500 and, under python -O, was skipped entirely: forking an
unknown env then raised KeyError and a named trace update read past the
data it was given. Raise HTTPError(400) like the other checks do.
Places the two test files dev added into the new layout, and points the
new storage-wiring test at env_payload: it called the local _env helper
this branch had already replaced, which merged cleanly and then failed.
Brings in dev along with the layout placement and the env_payload fix
made on the PR-1 branch. D1 and D2 both survive the auto-merge of
server_utils.py and web_handlers.py.
Replaces the background event loop and requests session with the
AsyncHTTPTestCase base class from PR-1, which already runs the app
in-process on an ephemeral port. The four integration files become
TestCase subclasses; pytest still collects and marks them.
first/second read as two windows; they are the id returned by each call,
which is the same id both times. Also assert only one pane exists.
The guidance still said VisdomHTTPTestCase was scheduled for replacement
by a background-loop fixture. Record the opposite, and the consequences
for anyone writing an HTTP test: no fixtures, no parametrize, share via
a base class.
Both halves now run off VisdomHTTPTestCase instead of their own fixture block.
The three cap tables collapse onto parametrize; the file was untracked until now.
Guard the missing-point check behind a numeric test, and stop indexing data and
traces past their length when an update supplies fewer entries than the plot.
It was the one history pane that grew without bound.
Removing a heatmap names no trace and posts no data, so the shortcut for
opts-only updates returned before the delete branch and left the plot up.
Polling had no tests at all, while AGENTS.md asks for every socket
feature to work over both transports. Covers minting a sid on each
route, the handshake, the three protocol failures, ten commands driven
end to end over HTTP, the readonly short-circuit, the idle reaper and
the pending-message deque.

Two behaviours are pinned rather than changed: a polling subscriber
receives a fourth, redundant layout_update because it registers before
initialize broadcasts, and the deque is unbounded, which is what makes
the reaper load-bearing.
The submitted username and derived key were checked with ==, which
short-circuits on the first differing character. That leaks, through
response timing, how much of a guess was correct, and the short-circuit
between the two checks leaked whether the username alone was right.
hmac.compare_digest on both halves removes the signal.
-readonly stopped socket commands and blocked uploads and experiment
logging, but the HTTP routes that create, update, close, fork, delete
and save were left open, so any client could still mutate a server
started readonly. Adds a check_readonly decorator next to check_auth and
puts it on those six endpoints, plus the one write hidden behind
/win_data, which also serves reads and so checks inline.

readonly moves onto _WEB_APP_ATTRIBUTES, which is where every other
per-request attribute already comes from; the two handlers that copied
it by hand no longer need an initialize override.
Neither gate had any tests. Covers the login page and its form, the four
ways a credential can be wrong, 401 on every authenticated route with
the state left untouched, the same routes succeeding with the issued
cookie, a forged cookie, /health staying public by design, and both
socket kinds closing instead of registering when unauthenticated.

The readonly half asserts 403 and no state change for each of the nine
mutating routes, that reads and the env page still work, and that an
ordinary server still answers 200 on all of them -- otherwise a
decorator that refused everything would look like a pass.
write_error rendered the exception, its traceback and request.__dict__
whenever tornado's debug flag was set, and app.py set that flag
unconditionally -- so every deployment served its own source paths and
request internals on any 500, and error.html's production branch was
unreachable. The flag also turned on autoreload for every server as a
side effect.

Replaces it with a show_error_details setting driven by the root logging
level, so -logging_level DEBUG brings the detail back and nothing else
changes with it.
TestClientMessageShapes built its client with Visdom(send=False) but left
use_incoming_socket at its default, so every one of its six tests opened an
incoming socket and waited out the connect timeout: 6.30s each, 37.8s of the
file's 37.99s and of the whole suite's 43s.

Those six drive no Application and no HTTP, so they belong in unit/ on the
offline_client fixture rather than here; they move to unit/client_content.py.
The two AsyncHTTPTestCase classes stay TestCases, as the HTTP round trip
requires, and lose their duplicated setUp/get_app/post_json to
VisdomHTTPTestCase. The readonly class expresses its server through the
app_kwargs hook the base class already provides.

The file now runs in 0.17s instead of 37.99s.
Adds unit/client_content.py: text, properties, table, embeddings and its
event handlers, learning_curve, update_window_opts, the window and env writes,
and the four methods that parse the server's reply rather than returning it.
The experiment message-shape tests move here from integration/.

The reply parsers cannot use capture_send -- with send=False, _send returns a
(msg, endpoint) tuple and json.loads chokes on it -- so they patch _send with
a canned reply instead.

Fixes get_env_list, which was documented and typed as returning a list of env
names but returned the current env's pane dict. _send defaults a missing eid
to the client's env, and /env_state answers with one env's windows whenever it
is given an eid, returning the env list only when it is not. A new
default_eid=False keyword lets a caller opt out of that defaulting; every
route that wants the current env is unaffected.

Two behaviours are pinned rather than changed: properties validates none of
the five property types it documents, and embeddings raises on a client with
no incoming socket unless opts.register_embedding_events is False.
Eight files carried no module-level marker, so -m unit and -m integration
selected 1165 of 1428 tests between them and 263 were in neither bucket. With
the markers backfilled the two selections now sum to the whole suite, which is
the property the new CI split depends on. unit/server_utils.py was also
missing the license header AGENTS.md requires.

python-tests.yml gains a unit job that runs in about a second and gates the
3.12/3.13 matrix, so an obvious break fails before three torch installs
happen. The matrix job now runs with --cov-fail-under=80 against a measured
84%; the gap is deliberate headroom so an unrelated PR does not go red on
rounding. The flags live in the workflow rather than in pyproject's addopts,
because a floor is meaningless on the single-file runs done while writing a
test and addopts would make every local pytest hard-require pytest-cov.

Documents the marker meanings, the bucket-sum invariant and the socket
timeout that made the suite slow, so the next person does not reintroduce it.
Drops --cov-fail-under from the workflow. CI still runs --cov=visdom
--cov-report=term-missing, so the number is on every run and the next PR can
pick a threshold from real data instead of guessing one.

Choosing that threshold is its own decision and does not belong bundled with
the suite work. The candidates are not equivalent: 84 is an exact ratchet with
no slack for the fact that CI has torch and av installed where a dev machine
may not, and 100 is unreachable without either covering the sklearn logger --
whose autolog() monkey-patches every estimator with no un-patch API -- or
pragma-ing out roughly 500 lines, which would make the number meaningless.

The docs now say coverage is reported rather than enforced, and record what a
future floor has to account for.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Manik-Khajuria-5, your pull request is larger than the review limit of 150000 diff characters

@sourcery-ai

sourcery-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds a comprehensive unit/integration test suite around client content panes, server env/window lifecycle, and sockets; introduces durability and name-collision fixes in JSONStore; strengthens server-side safety (readonly enforcement, safer compare_envs, plot history caps, constant‑time auth) and splits pytest suite into unit/integration with CI coverage gating.

Sequence diagram for get_env_list env_state behavior

sequenceDiagram
    participant Client as VisdomClient
    participant Send as _send
    participant Server as EnvStateHandler.post

    Client->>Client: get_env_list()
    Client->>Send: _send({}, endpoint=env_state, quiet=True, default_eid=False)
    Send->>Server: POST /env_state (no eid)
    Server-->>Send: JSON env_list
    Send-->>Client: env_list JSON
    Client-->>Client: json.loads(...) -> list of env names
Loading

File-Level Changes

Change Details Files
Add extensive unit tests for data model durability, LazyEnvData, client helpers, metrics and media payloads, plus integration tests for HTTP/socket behavior and environment lifecycle.
  • Expand py/tests/unit/data_model.py with durability tests for JSONStore env/undo saves, hash-fallback files, LazyEnvData semantics, deep-copy behavior, and name-collision edge cases.
  • Add multiple new unit modules (client_helpers, client_metrics, client_payloads_media, client_payloads_graph, client_payloads_shapes, client_content, compare_envs, memory_caps, shared_utils, tsne, run_server_cli, window_builder, server_utils, experiment_store, smoke, plots, socket_setup) to cover client-side helpers, metrics, media formats, server utilities, and TSNE backend selection without needing a live server.
  • Introduce integration tests (integration/socket_commands.py, auth.py, polling_parity.py, update_plots.py, env_transfer.py, window_lifecycle.py, environment_lifecycle.py, storage_wiring.py, edge_cases.py, build_verification.py, window_types.py, update_text_media.py, socket_lifecycle.py) that drive a real Application over HTTP and socket doubles to exercise routes like /events, /update, /env_state, /upload_env, socket polling, and command dispatch.
  • Provide shared test utilities in py/tests/testutils (HTTP base class, fake handlers/sockets/stores, payload builders, socket doubles), and a manual visual_check.py script under example/manual for human UI verification.
py/tests/unit/data_model.py
py/tests/unit/*.py
py/tests/integration/*.py
py/tests/testutils/*.py
example/manual/visual_check.py
example/manual/README.md
Make JSONStore environment and undo writes atomic, robust to interruptions, and correctly handle hash-fallback filenames and name collisions.
  • Add JSONStore._atomic_write that writes to .tmp and uses os.replace for both env and undo saves, ensuring truncated writes do not corrupt the main file.
  • Refactor serialize_env to route both primary and hash-fallback writes through _atomic_write, preserving existing envs if ENAMETOOLONG/206 is raised and ensuring .tmp files are never treated as envs by list_envs.
  • Refactor save_undo to use atomic_write for both plain and hashed undo stacks, keeping interrupted undo saves from destroying existing stacks.
  • Document and test behavior around hash_fallback files: list_envs exposes the real id from hashed files while env ids that look like hash<64hex> are intentionally omitted from listings to avoid colliding with fallback filenames.
py/visdom/data_model/json_store.py
py/tests/unit/data_model.py
Harden server-side handlers: readonly enforcement, safer env/window operations, improved socket behavior, and lower-leak error handling.
  • Introduce check_readonly decorator and reject_readonly helper in server_utils, applying them to PostHandler, UpdateHandler.post, CloseHandler.post, DeleteEnvHandler.post, ForkEnvHandler.post, SaveEnvHandler.post, UploadEnvHandler.post, and ExperimentLogHandler.post, so readonly servers respond 403 for writes while still allowing reads (with a special-case write path inside EnvStateHandler.wrap_func).
  • Fix compare_envs to handle panes without content or data safely, skip unnamed or malformed plot traces, and treat envs with missing or malformed windows as no-ops instead of raising, while maintaining deep-copy semantics so source envs remain untouched.
  • Adjust register_window to assign pane indices based on max existing index instead of len(env), avoiding index reuse after deletions and ensuring window ordering remains consistent with undo behavior.
  • Move socket broadcast_layouts to BaseSocketHandler, ensure save_layouts uses it for both polling and websocket sources, fix delete pane close event to only pop once under escaped eid, and guard embeddings pop against empty or missing old_content to avoid IndexError/KeyError on sockets.
  • Tighten socket message validation: reject non-list or non-int frame indices for plot_history updates, and ensure EnvStateHandler's read branch raises HTTPError 400 when a window is missing instead of an assertion.
  • Add constant-time username/password comparison in LoginHandler.post using hmac.compare_digest and adjust BaseHandler.write_error to use show_error_details flag instead of tornado debug, so traceback/request bodies are only shown when logging is DEBUG.
  • Remove UploadEnvHandler and ExperimentLogHandler.initialize overrides that just copied app.readonly, relying instead on BaseHandler's initialize and new readonly plumbing.
py/visdom/utils/server_utils.py
py/visdom/server/handlers/web_handlers.py
py/visdom/server/handlers/socket_handlers.py
py/visdom/server/handlers/base_handlers.py
py/visdom/server/app.py
py/tests/integration/*.py
Expand client API behavior: fix env list retrieval, adjust image grid placement, support extra axis options, and ensure TSNE backend selection is robust.
  • Extend Visdom._send signature with default_eid flag; when False, messages without eid leave it unset instead of defaulting to the client env. Use this in get_env_list so /env_state returns the env list rather than a single env's windows, while preserving default behavior elsewhere.
  • Adjust images() grid placement so h_start and w_start are computed as yheight+padding and xwidth+padding (removing the extra +1), ensuring padding=0 does not write out of bounds and images are centered properly within their cells.
  • Update _axisformat to include xtickstep/ytickstep (tickstep) in the gate and mapping to Plotly's dtick, allowing axis step-only opts to take effect even when no other axis options are set.
  • Wrap _normalize_labels' numeric check in np.errstate(invalid='ignore') to avoid runtime warnings when labels contain infinities, treating non-finite labels as invalid and raising a clear AssertionError instead.
  • Refine _axisformat3d ticks behavior to compute nticks from tickstep only when both tickmin and tickmax are present, and add tests around 3D axis behavior, layout margins, and title handling.
  • Add unit tests for TSNE backend selection, verifying openTSNE is preferred when available, bhtsne is used as a fallback, and do_tsne errors mention both backends when neither is importable.
  • Ensure _handle_post/get_env_list/get_env_state/delete_envs behaviors are fully tested with patched _send responses and offline clients.
py/visdom/__init__.py
py/tests/unit/client_helpers.py
py/tests/unit/client_metrics.py
py/tests/unit/client_payloads_media.py
py/tests/unit/tsne.py
Introduce memory caps for server-side histories (text, image, embeddings, plot history) and thread them through Application/handlers.
  • Add DEFAULT_MAX_PLOT_HISTORY constant to server defaults and store it on Application as max_plot_history, copying it into web handlers (BaseHandler) alongside max_text_lines, max_old_content, and max_image_history.
  • Extend UpdateHandler.update signature to accept max_plot_history and apply it to plot_history panes: when appending frames, truncate p['content'] to the last max_plot_history frames and keep selected index valid.
  • Ensure image_history updates respect max_image_history and keep 'selected' within range; these behaviors are covered in unit/image_slider.py and integration/update_text_media.py.
  • Apply max_old_content to embeddings old_content via update_embeddings_packet, trimming history to a fixed depth and avoiding unbounded growth when repeatedly drilling down.
  • Add unit tests in memory_caps.py that drive UpdateHandler.update/update_embeddings_packet with small caps, verifying truncation keeps newest entries and selected indices remain valid.
py/visdom/server/defaults.py
py/visdom/server/app.py
py/visdom/server/handlers/base_handlers.py
py/visdom/server/handlers/web_handlers.py
py/tests/unit/image_slider.py
py/tests/unit/memory_caps.py
Restructure pytest suite into unit/integration, refine discovery, and add CI gating with coverage reporting.
  • Move existing tests from py/tests/test_.py into py/tests/unit/ and py/tests/integration/, adding module-level pytestmark = pytest.mark.unit / integration to ensure -m unit and -m integration partition the suite completely.
  • Update pyproject.toml pytest configuration: set testpaths=['py/tests'], add pythonpath=['py','py/tests'], broaden python_files to ['.py'], exclude testutils via norecursedirs so helpers remain importable but uncollected, and register new markers (unit, integration, slow, server) with clearer descriptions.
  • Update .agents/context/testing.md and AGENTS.md with detailed guidance on where tests belong (unit vs integration), how to use VisdomHTTPTestCase, which markers to apply, and how to run fast/unit vs matrix/coverage jobs.
  • Adjust setup.py find_packages(where='py') to exclude ['tests','tests.*'], ensuring py/tests is not packaged, and add a note about testutils being a package reachable via pythonpath.
  • Add a new GitHub Actions job 'unit' in python-tests.yml that runs pytest -m unit on Python 3.12 as a fast gate, and extend the existing pytest job to depend on it and run pytest -m "not server" with --cov=visdom --cov-report=term-missing, keeping coverage flags in CI rather than pyproject addopts.
  • Document current overall coverage (~84%) and caveats around untested modules (loggers/sklearn.py, pytorch.py) in context/testing.md to inform future --cov-fail-under thresholds.
py/tests/unit/*.py
py/tests/integration/*.py
.agents/context/testing.md
AGENTS.md
pyproject.toml
setup.py
.github/workflows/python-tests.yml
Refine experiment logging tests to use VisdomHTTPTestCase and move client message-shape tests into unit coverage.
  • Refactor py/tests/test_experiment_log_handler.py into py/tests/integration/experiment_log_handler.py, switching from bare AsyncHTTPTestCase to VisdomHTTPTestCase, removing ad-hoc tempdir setup and post_json helpers in favor of the shared HTTP base.
  • Remove client-side experiment/log_metrics/finish_experiment message shape tests from the integration file and reintroduce them as offline-client unit tests in py/tests/unit/client_content.py using the offline_client fixture and capture_send, eliminating the 6.3s per-test socket timeout caused by constructing Visdom(send=False) without use_incoming_socket=False.
  • Ensure readonly experiment endpoints are tested via TestExperimentLogReadonly using VisdomHTTPTestCase.app_kwargs={'readonly':True}, verifying 403 responses and no persisted experiments.
  • Cut experiment_log_handler's runtime from ~38s to ~0.17s by avoiding socket timeouts and reusing the HTTP base.
py/tests/integration/experiment_log_handler.py
py/tests/unit/client_content.py

Possibly linked issues

  • #0: PR changes UpdateHandler.update signature usage in tests (e.g., image_slider) to match implementation, resolving the TypeError.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a Python test suite (pytest) for the server and client

1 participant