Compare commits

..
18 Commits
Author SHA1 Message Date
atarashansky 044720e13f tech: test tests using latest installations 2023-09-19 13:57:59 -07:00
maniarathi 2d7aab3a9a fix: override default so that issues are not marked as stale (#2627) 2023-08-23 21:22:17 -04:00
maniarathi f749733d54 feat: Add a Github Action that automatically closes stale PRs. (#2626) 2023-08-22 22:08:22 -04:00
atarashanskyandatarashansky ffcf6eb5d8 chore: Release version 1.1.2 (#2611)
* Bump version: 1.1.1 → 1.1.2-rc.0

* fix: release candidate 1.1.2

* Bump version: 1.1.2-rc.0 → 1.1.2

* promote

---------

Co-authored-by: atarashansky <atarashansky@CZIMACOS3990.hsd1.ma.comcast.net>
2023-04-26 15:01:57 -04:00
atarashanskyandatarashansky c209a9bca7 fix: pin flask requirement to be less than 2.3 (#2609)
Co-authored-by: atarashansky <atarashansky@CZIMACOS3990.hsd1.ma.comcast.net>
2023-04-26 13:58:40 -04:00
Kuni Katsuya 85319d45a4 chore: tech issue template 2023-02-06 15:46:54 -08:00
Andrew Tolopko 514f1627ea Update license copyright year (#2600) 2023-02-03 16:01:53 -05:00
Severiano Badajoz 127de34a20 feat: Add PR Linting (#2560) 2022-10-24 18:08:25 +00:00
Andrew Tolopko 54ab9d79b6 docs: fix test pypi install command (#2515)
fix test pypi install command in release_process.md
2022-09-29 19:30:11 +00:00
Andrew Tolopko f48d06fb90 Bump version: 1.1.0 → 1.1.1 (#2572) 2022-09-21 15:33:28 -04:00
Severiano BadajozandSeve Badajoz 84563291a0 fix: fix static file serving in webpack (#2574)
Co-authored-by: Seve Badajoz <severiano.badajoz@chanzuckerberg.com>
2022-09-21 18:03:03 +00:00
Andrew Tolopko ddb601c103 feat: annotate command improvements (#2568)
* Replace --input-h5ad-file with a positional argument, for consistency with other CLI commands
* Replace --update-h5ad-file with --overwrite, for consistency with `prepare` command.
* Fix/clarify various help descriptions
* Fix final output message when input file is overwritten
* Fix annotate top-level help description
2022-09-15 11:55:58 -04:00
ashin-czi 450261f109 chore: updating Annotate favicon and logo icon (#2556)
* chore: replacing html icon with png icon and updating favicon
2022-08-25 16:01:03 +00:00
ashin-czi c0f4ad6dfa docs: updating readme and display version for rebranding (#2550)
* docs: updating readme and display version for rebranding

- CELLxGENE -> CELLxGENE Annotate
- reverting __init__.py display_version back to "cellxgene"
- changing page titles to "CELLxGENE | Annotate"
2022-08-25 15:41:26 +00:00
atarashanskyandatarashansky ff5da77372 fix unit tests (#2562)
Co-authored-by: atarashansky <atarashansky@CZIMACOS3990.local>
2022-08-25 08:02:58 -07:00
a9044b01df release version 1.1.0 (#2548)
* Bump version: 1.0.1 → 1.1.0-rc.0

* bump version to v1.1.0

* Bump version: 1.1.0-rc.0 → 1.1.0-rc.1

* bump version to v1.1.0 rc1

rc0 was previously used by an aborted release attempt

* Bump version: 1.1.0-rc.1 → 1.1.0

Co-authored-by: Seve Badajoz <severiano.badajoz@chanzuckerberg.com>
Co-authored-by: Severiano Badajoz <sbadajoz@chanzuckerberg.com>
2022-08-23 10:02:23 -07:00
ashin-czi 11b948369f fix: reverting back to old icon 2022-08-18 14:49:59 -04:00
ashin-czi a2dc0c25b1 chore: updating Annotate favicon 2022-08-11 13:30:19 -04:00
23 changed files with 202 additions and 106 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 1.0.1 current_version = 1.1.2
commit = True commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<prerel>rc)\.(?P<prerelversion>\d+))? parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<prerel>rc)\.(?P<prerelversion>\d+))?
serialize = serialize =
+23
View File
@@ -0,0 +1,23 @@
---
name: Tech Issue
about: Engineering-specific technical work that is not product-specific. Engineering team "owns" these issues.
title: ""
labels: tech
assignees: ""
---
## Motivation
Why is this work important to engineers?
## Definition of Done
What should the end result look like? What will have been changed?
## Tasks
Detail the specific tasks that can be used to accomplish the desired changes.
If detailed steps cannot be provided at this time, please file a [Tech Proposal](https://docs.google.com/document/d/1o2vuvl-kXwRJN1nBoPzJS_MAQgDGYnjmPZWa4qRDi-I/edit#heading=h.7dvzhm7gqc3v) instead.
- [ ]
- [ ]
+23
View File
@@ -0,0 +1,23 @@
name: Close inactive pull requests
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
with:
days-before-issue-stale: -1 # Do not mark any issues as stale
days-before-pr-stale: 14
days-before-pr-close: 3
stale-pr-message: "This PR has not seen any activity in the past 2 weeks; if no one comments or reviews it in the next 3 days, this PR will be closed."
close-pr-message: "This PR was closed because it has been inactive for 17 days, 3 days since being marked as stale. Please re-open if you still need this to be addressed."
stale-pr-label: "stale"
close-pr-label: "autoclosed"
exempt-draft-pr: true
repo-token: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,19 @@
name: "Lint PR commit message"
on:
pull_request_target:
types:
- opened
- edited
- synchronize
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v3.4.1
with:
validateSingleCommit: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2017-2022 Chan Zuckerberg Initiative Copyright (c) 2017-2023 Chan Zuckerberg Initiative
Permission is hereby granted, free of charge, to any person obtaining a copy of Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in this software and associated documentation files (the "Software"), to deal in
+17 -17
View File
@@ -7,27 +7,27 @@ _an interactive explorer for single-cell transcriptomics data_
[![Compatibility Tests](https://github.com/chanzuckerberg/cellxgene/workflows/Compatibility%20Tests/badge.svg)](https://github.com/chanzuckerberg/cellxgene/actions?query=workflow%3A%22Compatibility+Tests%22) [![Compatibility Tests](https://github.com/chanzuckerberg/cellxgene/workflows/Compatibility%20Tests/badge.svg)](https://github.com/chanzuckerberg/cellxgene/actions?query=workflow%3A%22Compatibility+Tests%22)
![Code Coverage](https://codecov.io/gh/chanzuckerberg/cellxgene/branch/main/graph/badge.svg) ![Code Coverage](https://codecov.io/gh/chanzuckerberg/cellxgene/branch/main/graph/badge.svg)
cellxgene Desktop (pronounced "cell-by-gene") is an interactive data explorer for single-cell datasets, such as those coming from the [Human Cell Atlas](https://humancellatlas.org). Leveraging modern web development techniques to enable fast visualizations of at least 1 million cells, we hope to enable biologists and computational researchers to explore their data. CZ CELLxGENE Annotate (pronounced "cell-by-gene") is an interactive data explorer for single-cell datasets, such as those coming from the [Human Cell Atlas](https://humancellatlas.org). Leveraging modern web development techniques to enable fast visualizations of at least 1 million cells, we hope to enable biologists and computational researchers to explore their data.
Whether you need to visualize one thousand cells or one million, cellxgene Desktop helps you gain insight into your single-cell data. Whether you need to visualize one thousand cells or one million, CELLxGENE Annotate helps you gain insight into your single-cell data.
<img src="https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/crossfilter.gif" width="350" height="200" hspace="30"><img src="https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/category-breakdown.gif" width="350" height="200" hspace="30"> <img src="https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/crossfilter.gif" width="350" height="200" hspace="30"><img src="https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/category-breakdown.gif" width="350" height="200" hspace="30">
# Getting started # Getting started
### The comprehensive guide to cellxgene Desktop ### The comprehensive guide to CZ CELLxGENE Annotate
[The cellxgene documentation is your one-stop-shop for information about cellxgene Desktop](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/README.md)! You may be particularly interested in: [The CZ CELLxGENE Annotate documentation is your one-stop-shop for information about CELLxGENE Annotate](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/README.md)! You may be particularly interested in:
- Seeing [what cellxgene Desktop can do](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/explore-data/explorer-tutorials.md) - Seeing [what Annotate can do](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/explore-data/explorer-tutorials.md)
- Learning more about cellxgene [installation](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/install.md) and [usage](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/quick-start.md#quick-start-1) - Learning more about Annotate [installation](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/install.md) and [usage](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/quick-start.md#quick-start-1)
- [Preparing your own data](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/data-reqs.md) for use in cellxgene Desktop - [Preparing your own data](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/data-reqs.md) for use in Annotate
- Checking out [our roadmap](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/roadmap.md) for future development - Checking out [our roadmap](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/roadmap.md) for future development
- [Contributing](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/contribute.md) to cellxgene Desktop - [Contributing](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/contribute.md) to Annotate
### Quick start ### Quick start
To install cellxgene Desktop you need Python 3.6+. We recommend [installing cellxgene Desktop into a conda or virtual environment.](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/install.md) To install CELLxGENE Annotate you need Python 3.6+. We recommend [installing Annotate into a conda or virtual environment.](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/install.md)
Install the package. Install the package.
@@ -35,19 +35,19 @@ Install the package.
pip install cellxgene pip install cellxgene
``` ```
Launch cellxgene Desktop with an example [anndata](https://anndata.readthedocs.io/en/latest/) file Launch Annotate with an example [anndata](https://anndata.readthedocs.io/en/latest/) file
```bash ```bash
cellxgene launch https://cellxgene-example-data.czi.technology/pbmc3k.h5ad cellxgene launch https://cellxgene-example-data.czi.technology/pbmc3k.h5ad
``` ```
To explore more datasets already formatted for cellxgene Desktop, check out the [Demo data](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/quick-start.md#example-datasets) or To explore more datasets already formatted for Annotate, check out the [Demo data](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/quick-start.md#example-datasets) or
see [Preparing your data](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/data-reqs.md) to learn more about formatting your own see [Preparing your data](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/desktop/data-reqs.md) to learn more about formatting your own
data for cellxgene Desktop. data for CELLxGENE Annotate.
### Supported browsers ### Supported browsers
cellxgene Desktop currently supports the following browsers: CELLxGENE Annotate currently supports the following browsers:
- Google Chrome 61+ - Google Chrome 61+
- Edge 15+ - Edge 15+
@@ -62,11 +62,11 @@ For questions, suggestions, or accolades, [join the `#cellxgene-users` channel o
For any errors, [report bugs on Github](https://github.com/chanzuckerberg/cellxgene/issues). For any errors, [report bugs on Github](https://github.com/chanzuckerberg/cellxgene/issues).
# Developing with cellxgene Desktop # Developing with CZ CELLxGENE Annotate
### Contributing ### Contributing
We warmly welcome contributions from the community! Please see our [contributing guide](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/contribute.md) and don't hesitate to open an issue or send a pull request to improve cellxgene Desktop. Please see the [dev_docs](https://github.com/chanzuckerberg/cellxgene/tree/main/dev_docs) for pull request suggestions, unit test details, local documentation preview, and other development specifics. We warmly welcome contributions from the community! Please see our [contributing guide](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/contribute.md) and don't hesitate to open an issue or send a pull request to improve CELLxGENE Annotate. Please see the [dev_docs](https://github.com/chanzuckerberg/cellxgene/tree/main/dev_docs) for pull request suggestions, unit test details, local documentation preview, and other development specifics.
This project adheres to the Contributor Covenant [code of conduct](https://github.com/chanzuckerberg/.github/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to opensource@chanzuckerberg.com. This project adheres to the Contributor Covenant [code of conduct](https://github.com/chanzuckerberg/.github/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to opensource@chanzuckerberg.com.
@@ -77,11 +77,11 @@ As such, we encourage other scientific tool builders in academia or industry to
this project. All code is freely available for reuse under the [MIT license](https://opensource.org/licenses/MIT). this project. All code is freely available for reuse under the [MIT license](https://opensource.org/licenses/MIT).
Before extending cellxgene, we encourage you to reach out to us with ideas or questions. It might be possible that an Before extending CELLxGENE Annotate, we encourage you to reach out to us with ideas or questions. It might be possible that an
extension could be directly contributed, which would make it available for a wider audience, or that it's on our extension could be directly contributed, which would make it available for a wider audience, or that it's on our
[roadmap](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/roadmap.md) and under active development. [roadmap](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/roadmap.md) and under active development.
See the [cellxgene extensions](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/community-extensions.md) section of our documentation for examples of community use and cellxgene extensions. See the [CELLxGENE extensions](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/community-extensions.md) section of our documentation for examples of community use and CELLxGENE extensions.
### Security ### Security
@@ -9,6 +9,7 @@ const sharedConfig = require("./webpack.config.shared");
const babelOptions = require("../babel/babel.dev"); const babelOptions = require("../babel/babel.dev");
const fonts = path.resolve("src/fonts"); const fonts = path.resolve("src/fonts");
const images = path.resolve("src/images");
const nodeModules = path.resolve("node_modules"); const nodeModules = path.resolve("node_modules");
const devConfig = { const devConfig = {
@@ -28,11 +29,11 @@ const devConfig = {
{ {
test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2|otf)$/i, test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2|otf)$/i,
loader: "file-loader", loader: "file-loader",
include: [nodeModules, fonts], include: [nodeModules, fonts, images],
options: { options: {
name: "static/assets/[name].[ext]", name: "static/assets/[name].[ext]",
// (thuang): This is needed to make sure @font url path is '/static/assets/' // (thuang): This is needed to make sure @font url path is '/static/assets/'
publicPath: "/", publicPath: "..",
}, },
}, },
], ],
@@ -14,6 +14,7 @@ const CspHashPlugin = require("./cspHashPlugin");
const sharedConfig = require("./webpack.config.shared"); const sharedConfig = require("./webpack.config.shared");
const fonts = path.resolve("src/fonts"); const fonts = path.resolve("src/fonts");
const images = path.resolve("src/images");
const nodeModules = path.resolve("node_modules"); const nodeModules = path.resolve("node_modules");
const prodConfig = { const prodConfig = {
@@ -43,11 +44,11 @@ const prodConfig = {
{ {
test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2|otf)$/i, test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2|otf)$/i,
loader: "file-loader", loader: "file-loader",
include: [nodeModules, fonts], include: [nodeModules, fonts, images],
options: { options: {
name: "static/assets/[name]-[contenthash].[ext]", name: "static/assets/[name]-[contenthash].[ext]",
// (thuang): This is needed to make sure @font url path is '../static/assets/' // (thuang): This is needed to make sure @font url path is '../static/assets/'
publicPath: "static/", publicPath: "..",
}, },
}, },
], ],
+1 -1
View File
@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>cell&times;gene</title> <title>CELL&times;GENE | Annotate</title>
<style> <style>
html, html,
body, body,
+1 -1
View File
@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>cell&times;gene</title> <title>CELL&times;GENE | Annotate</title>
<style> <style>
html, html,
body, body,
+5 -3
View File
@@ -1,12 +1,12 @@
{ {
"name": "cellxgene", "name": "cellxgene",
"version": "1.0.1", "version": "1.1.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "cellxgene", "name": "cellxgene",
"version": "1.0.1", "version": "1.1.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/eslint-parser": "^7.15.0", "@babel/eslint-parser": "^7.15.0",
@@ -21331,7 +21331,9 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"dev": true, "dev": true,
"requires": {} "requires": {
"ajv": "^8.0.0"
}
}, },
"ajv-keywords": { "ajv-keywords": {
"version": "5.1.0", "version": "5.1.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "cellxgene", "name": "cellxgene",
"version": "1.0.1", "version": "1.1.2",
"license": "MIT", "license": "MIT",
"description": "cellxgene is a web application for the interactive exploration of single cell sequence data.", "description": "cellxgene is a web application for the interactive exploration of single cell sequence data.",
"repository": "https://github.com/chanzuckerberg/cellxgene", "repository": "https://github.com/chanzuckerberg/cellxgene",
+1 -1
View File
@@ -41,7 +41,7 @@ class App extends React.Component {
const { loading, error, graphRenderCounter } = this.props; const { loading, error, graphRenderCounter } = this.props;
return ( return (
<Container> <Container>
<Helmet title="cellxgene" /> <Helmet title="CELL&times;GENE | Annotate" />
{loading ? ( {loading ? (
<div <div
style={{ style={{
+7 -9
View File
@@ -1,17 +1,15 @@
import React from "react"; import React from "react";
import * as globals from "../../globals"; import icon from "../../images/icon.png";
const Logo = (props) => { const Logo = (props) => {
const { size } = props; const { size } = props;
return ( return (
<svg width={size} height={size} viewBox="0 0 48 48" fill="none"> <img
<rect width="48" height="48" fill="white" /> src={icon}
<rect width="48" height="48" fill={globals.logoColor} /> height={size}
<rect x="19" y="19" width="22" height="22" fill="white" /> width={size}
<rect x="24" y="24" width="12" height="12" fill={globals.logoColor} /> alt="CELLxGENE Annotate Logo"
<rect x="7" y="19" width="7" height="22" fill="white" /> />
<rect x="19" y="7" width="22" height="7" fill="white" />
</svg>
); );
}; };
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

+2 -2
View File
@@ -26,14 +26,14 @@ Steps must be run from the project directory and in a virtual env with all the d
3. In the release branch, run `make create-release-candidate PART=[major | minor | patch]`. This will bump the version and create a release *candidate* version (e.g. `0.3.0-rc.0`). 3. In the release branch, run `make create-release-candidate PART=[major | minor | patch]`. This will bump the version and create a release *candidate* version (e.g. `0.3.0-rc.0`).
4. Commit changes, push the new branch to origin and open a `DO NOT MERGE` draft PR, which will run tests on your branch. We will use this PR later 4. Commit changes, push the new branch to origin and open a `DO NOT MERGE` draft PR, which will run tests on your branch. We will use this PR later
5. Upload the release candidate to Test PyPI by running the command `make release-candidate-to-test-pypi`. (Make sure you are registered for PyPI and Test PyPI and you have write access to the cellxgene PyPI package for both). 5. Upload the release candidate to Test PyPI by running the command `make release-candidate-to-test-pypi`. (Make sure you are registered for PyPI and Test PyPI and you have write access to the cellxgene PyPI package for both).
6. Verify the release candidate in a fresh virtual environment by running `make install-release-test` which installs the cellxgene build you just uploaded to Test PyPI. The PM should do this too. 6. Verify the release candidate in a fresh virtual environment by running `VERSION=<X>.<Y>.<Z>rc.<#> make install-release-test` which installs the cellxgene build you just uploaded to Test PyPI (note that the version value does not include a dash `-`!). The PM should do this too. Note that you may need to run `hash -r` to ensure the cellxgene executable that was just installed is found in your shell path.
7. If you find errors with the release candidate, fix them in main, rebase, and run `make recreate-release-candidate` to increment the release candidate version (i.e. `0.3.0-rc.0` -> `0.3.0-rc.1`). Then go back to Steps 5 and 6 to re-upload and re-test the new release candidate. 7. If you find errors with the release candidate, fix them in main, rebase, and run `make recreate-release-candidate` to increment the release candidate version (i.e. `0.3.0-rc.0` -> `0.3.0-rc.1`). Then go back to Steps 5 and 6 to re-upload and re-test the new release candidate.
8. If everything looks good, push the release to Test PyPI without the release candidate tag by running the command `make release-final-to-test-pypi` (i.e. `0.3.0-rc.1` -> `0.3.0`). 8. If everything looks good, push the release to Test PyPI without the release candidate tag by running the command `make release-final-to-test-pypi` (i.e. `0.3.0-rc.1` -> `0.3.0`).
- **NOTE:** Once you push the final release version to Test PyPI, you cannot ever re-upload the build again. If you need to make changes to the build, you will have to "burn" the version number and bump the part again and go back to step 1 with a brand new version number. For example, if you upload `0.3.0` to Test PyPI and realize there's a bug, you will have to create a new version `0.4.0` and there will be no `0.3.0` version of cellxgene. This is why testing the release candidate is very important. - **NOTE:** Once you push the final release version to Test PyPI, you cannot ever re-upload the build again. If you need to make changes to the build, you will have to "burn" the version number and bump the part again and go back to step 1 with a brand new version number. For example, if you upload `0.3.0` to Test PyPI and realize there's a bug, you will have to create a new version `0.4.0` and there will be no `0.3.0` version of cellxgene. This is why testing the release candidate is very important.
9. Publish the open draft PR for the release and conduct a PR review. 9. Publish the open draft PR for the release and conduct a PR review.
10. Merge to the `main` branch. 10. Merge to the `main` branch.
11. Publish to PyPI (prod) (assuming you that you have registered for PyPI, and that you have write access to the cellxgene pypi package) by running `make release-final`. 11. Publish to PyPI (prod) (assuming you that you have registered for PyPI, and that you have write access to the cellxgene pypi package) by running `make release-final`.
12. Test the installation in a fresh virtual environment by running `pip install --no-cache-dir cellxgene`. 12. Test the installation in a fresh virtual environment by running `pip install --no-cache-dir cellxgene`. Note that you may need to run `hash -r` to ensure the cellxgene executable that was just installed is found in your shell path.
13. Create Github release using the version number and release notes ([instructions](https://help.github.com/articles/creating-releases/)): 13. Create Github release using the version number and release notes ([instructions](https://help.github.com/articles/creating-releases/)):
- Draft new release - Draft new release
- Type version name matching release version number from (1) - Type version name matching release version number from (1)
+1 -1
View File
@@ -2,7 +2,7 @@ import logging
import sys import sys
from server.common.utils.utils import import_plugins from server.common.utils.utils import import_plugins
__version__ = "1.0.1" __version__ = "1.1.2"
display_version = "cellxgene v" + __version__ display_version = "cellxgene v" + __version__
try: try:
+43 -32
View File
@@ -4,7 +4,7 @@ import os.path
import shlex import shlex
import shutil import shutil
import subprocess import subprocess
import sys from os.path import isfile
from subprocess import STDOUT, PIPE from subprocess import STDOUT, PIPE
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
@@ -27,23 +27,42 @@ def annotate_args(func):
@sort_options @sort_options
@click.command( @click.command(
short_help="Annotate H5AD file columns. Run `cellxgene annotation --help` for more information.", options_metavar="<options>"
options_metavar="<options>",
) )
@click.option( @click.argument(
"-i", "input_h5ad_file",
"--input-h5ad-file", type=click.Path(exists=True, dir_okay=False, readable=True),
nargs=1,
metavar="<path to H5AD input file>",
required=True, required=True,
type=str,
help="The input H5AD file containing the missing annotations.",
) )
@click.option( @click.option(
"-m", "-m",
"--model-url", "--model-url",
# Making this a required "option", rather than an "argument", since we support automatic model selection in the
# future, in which case the user would not need to specify this option at all and we can make it optional at
# that time.
required=True, required=True,
help="The URL of the model used to prediction annotated labels. May be a local filesystem directory " help="The URL of the model used to prediction annotated labels. May be a local filesystem directory "
"or S3 path (s3://)", "or S3 path (s3://)",
) )
@click.option(
"-o",
"--output-h5ad-file",
default="",
help="The output H5AD file that will contain the generated annotation values. If this option is not provided, "
"the input file will be overwritten to include the new annotations; in this case you must specify "
"--overwrite.",
metavar="<filename>",
)
@click.option(
"--overwrite",
default=False,
is_flag=True,
help="Allow overwriting of the specified H5AD output file, if it exists. For safety, you must specify this "
"flag if the specified output file already exists or if the --output-h5ad-file option is not provided.",
show_default=True,
)
@click.option( @click.option(
"-l", "-l",
"--counts-layer", "--counts-layer",
@@ -53,8 +72,8 @@ def annotate_args(func):
@click.option( @click.option(
"-g", "-g",
"--gene-column-name", "--gene-column-name",
help="The name of the `var` column that contains gene identifiers. The values in this column will be used to match " help="The name of the `var` column that contains gene names. The values in this column will be used to match "
"genes between the query and reference datasets. If not specified, the gene identifiers are expected to exist " "genes between the query and reference datasets. If not specified, the gene names are expected to exist "
"in `var.index`.", "in `var.index`.",
) )
# TODO: Useful if we want to support discoverability of models # TODO: Useful if we want to support discoverability of models
@@ -91,19 +110,6 @@ def annotate_args(func):
"will store the predicted annotation values and confidence scores. This can be used to allow multiple " "will store the predicted annotation values and confidence scores. This can be used to allow multiple "
"annotation predictions to be run on a single AnnData object.", "annotation predictions to be run on a single AnnData object.",
) )
@click.option(
"-u",
"--update-h5ad-file",
is_flag=True,
help="Flag indicating whether to update the input h5ad file with annotation values. This option is mutually "
"exclusive with --output-h5ad-file.",
)
@click.option(
"-o",
"--output-h5ad-file",
help="The output H5AD file that will contain the generated annotation values. This option is mutually "
"exclusive with --update-h5ad-file.",
)
@click.option("--use-model-cache/--no-use-model-cache", default=True) @click.option("--use-model-cache/--no-use-model-cache", default=True)
@click.option( @click.option(
"--use-gpu/--no-use-gpu", "--use-gpu/--no-use-gpu",
@@ -141,6 +147,9 @@ def annotate_args(func):
) )
@click.help_option("--help", "-h", help="Show this message and exit.") @click.help_option("--help", "-h", help="Show this message and exit.")
def annotate(**cli_args): def annotate(**cli_args):
"""
Add predicted annotations to an H5AD file. Run `cellxgene annotate --help` for more information.
"""
_validate_options(cli_args) _validate_options(cli_args)
print(f"Reading query dataset {cli_args['input_h5ad_file']}...") print(f"Reading query dataset {cli_args['input_h5ad_file']}...")
@@ -149,7 +158,11 @@ def annotate(**cli_args):
filter(None, [cli_args.get("annotation_prefix"), cli_args.get("annotation_type"), cli_args.get("run_name")]) filter(None, [cli_args.get("annotation_prefix"), cli_args.get("annotation_type"), cli_args.get("run_name")])
) )
output_h5ad_file = cli_args["input_h5ad_file"] if cli_args["update_h5ad_file"] else cli_args["output_h5ad_file"] output_h5ad_file = (
cli_args["input_h5ad_file"]
if cli_args["overwrite"] and not cli_args["output_h5ad_file"]
else cli_args["output_h5ad_file"]
)
model_url = cli_args.get("model_url") model_url = cli_args.get("model_url")
local_model_path = _retrieve_model(cli_args.get("model_cache_dir"), model_url, cli_args.get("use_model_cache")) local_model_path = _retrieve_model(cli_args.get("model_cache_dir"), model_url, cli_args.get("use_model_cache"))
@@ -196,7 +209,7 @@ def annotate(**cli_args):
p.wait() p.wait()
if p.returncode == 0: if p.returncode == 0:
print(f"Wrote annotations to {cli_args.get('output_h5ad_file')}") print(f"Wrote annotations to {output_h5ad_file}")
else: else:
print("Annotation failed!") print("Annotation failed!")
else: else:
@@ -218,13 +231,11 @@ def _retrieve_model(model_cache_dir, model_url, use_cache=True):
def _validate_options(cli_args): def _validate_options(cli_args):
# TODO(atolopko): Use cloup library for this logic output = cli_args["output_h5ad_file"]
if cli_args["update_h5ad_file"] and cli_args["output_h5ad_file"]: overwrite = cli_args["overwrite"]
click.echo("--update_h5ad_file and --output_h5ad_file are mutually exclusive")
sys.exit(1) if isfile(output) and not overwrite:
if not (cli_args["update_h5ad_file"] or cli_args["output_h5ad_file"]): raise click.UsageError(f"Cannot overwrite existing file {output}, try using the flag --overwrite")
click.echo("--update_h5ad_file or --output_h5ad_file must be specified")
sys.exit(1)
if __name__ == "__main__": if __name__ == "__main__":
+1 -2
View File
@@ -98,8 +98,7 @@ def custom_format_warning(msg, *args, **kwargs):
def jsonify_strict(data): def jsonify_strict(data):
return json.dumps(data, cls=StrictJSONEncoder, allow_nan=False) return StrictJSONEncoder().encode(data)
def import_plugins(plugin_module): def import_plugins(plugin_module):
""" """
+1 -1
View File
@@ -3,7 +3,7 @@
anndata>=0.7.6 # we need to_memory(), added in 0.7.6 anndata>=0.7.6 # we need to_memory(), added in 0.7.6
boto3>=1.12.18 boto3>=1.12.18
click>=7.1.2 click>=7.1.2
Flask>=1.0.2 Flask>=1.0.2,<2.3.0
Flask-Compress>=1.4.0 Flask-Compress>=1.4.0
Flask-Cors>=3.0.9 # CVE-2020-25032 Flask-Cors>=3.0.9 # CVE-2020-25032
Flask-RESTful>=0.3.6 Flask-RESTful>=0.3.6
+1 -1
View File
@@ -14,7 +14,7 @@ with open("server/requirements-annotate.txt") as fh:
setup( setup(
name="cellxgene", name="cellxgene",
version="1.0.1", version="1.1.2",
packages=find_packages(), packages=find_packages(),
url="https://github.com/chanzuckerberg/cellxgene", url="https://github.com/chanzuckerberg/cellxgene",
license="MIT", license="MIT",
+46 -27
View File
@@ -1,7 +1,7 @@
import os import os
import shutil import shutil
import unittest import unittest
from tempfile import mkstemp, TemporaryDirectory from tempfile import mkstemp, TemporaryDirectory, NamedTemporaryFile
import mlflow import mlflow
from click.testing import CliRunner from click.testing import CliRunner
@@ -12,10 +12,8 @@ from test.unit.cli.fixtures.mlflow_model_fixture import FakeModel
def write_model(model) -> str: def write_model(model) -> str:
with TemporaryDirectory() as mlflow_model_dir: with TemporaryDirectory() as mlflow_model_dir:
fixtures_path = os.path.join(os.path.dirname(__file__), 'fixtures') fixtures_path = os.path.join(os.path.dirname(__file__), "fixtures")
mlflow.pyfunc.save_model(mlflow_model_dir, mlflow.pyfunc.save_model(mlflow_model_dir, loader_module="fixtures", code_path=[fixtures_path])
loader_module='fixtures',
code_path=[fixtures_path])
return shutil.make_archive(mkstemp()[1], "zip", mlflow_model_dir) return shutil.make_archive(mkstemp()[1], "zip", mlflow_model_dir)
@@ -46,7 +44,6 @@ class TestCliAnnotate(unittest.TestCase):
result = CliRunner().invoke( result = CliRunner().invoke(
annotate, annotate,
[ [
"--input-h5ad-file",
query_dataset_file_path, query_dataset_file_path,
"--model-url", "--model-url",
model_file_path, model_file_path,
@@ -54,7 +51,8 @@ class TestCliAnnotate(unittest.TestCase):
f"{query_dataset_file_path}.output", f"{query_dataset_file_path}.output",
# avoid having mflow create conda env or virtualenv when in test env; # avoid having mflow create conda env or virtualenv when in test env;
# this avoids making pip remote requests and is also faster # this avoids making pip remote requests and is also faster
"--mlflow-env-manager", "local" "--mlflow-env-manager",
"local",
], ],
) )
@@ -74,31 +72,52 @@ class TestCliAnnotate(unittest.TestCase):
result.stdout, result.stdout,
"inputs passed correctly", "inputs passed correctly",
) )
def test__annotate__verifies_mutually_exclusive_options(self):
required_options = ["--input-h5ad-file", "some.h5ad", "--model-url", "some_url"]
result = CliRunner().invoke(
annotate,
required_options + [],
)
self.assertNotEqual(0, result.exit_code, "aborts with non-success code")
self.assertIn( self.assertIn(
"--update_h5ad_file or --output_h5ad_file must be specified", f"Wrote annotations to {query_dataset_file_path}.output",
result.stdout, result.stdout,
"error message displayed", "success message is correct",
) )
result = CliRunner().invoke( def test__annotate__requires_overwrite_option_when_output_file_exists(self):
annotate, required_options + ["--output-h5ad-file", "some_arg", "--update-h5ad-file"]
)
self.assertNotEqual(0, result.exit_code, "aborts with non-success code") with NamedTemporaryFile() as input_h5ad, NamedTemporaryFile() as existing_file:
self.assertIn( required_options = [input_h5ad.name, "--output-h5ad-file", existing_file.name, "--model-url", "some_url"]
"--update_h5ad_file and --output_h5ad_file are mutually exclusive", result = CliRunner().invoke(
result.stdout, annotate,
"error message displayed", required_options + [],
) )
self.assertNotEqual(0, result.exit_code, "aborts with non-success code")
self.assertIn(
"try using the flag --overwrite",
result.stdout,
"error message displayed",
)
def test__annotate__overwrite_option_allows_overwrite_of_existing_output_file(self):
model_file_path = write_model(FakeModel())
with NamedTemporaryFile() as existing_file:
required_options = [
existing_file.name,
"--output-h5ad-file",
existing_file.name,
"--overwrite",
"--model-url",
model_file_path,
]
result = CliRunner().invoke(
annotate,
required_options + [],
)
print(result.stdout)
self.assertNotEqual(1, result.exit_code, "aborts with non-success code")
self.assertIn(
f"Wrote annotations to {existing_file.name}",
result.stdout,
"success message is correct on output file overwrite",
)
# TODO: # TODO:
+1 -1
View File
@@ -54,5 +54,5 @@ class TestJsonifyStrict(unittest.TestCase):
# the actual test! # the actual test!
self.assertEqual( self.assertEqual(
jsonify_strict(values), jsonify_strict(values),
'{"floating": [100.0, 101.0, 102.0], "integer": [0, 1, 2, 3, 4, 5, 6, 7]}', '{"integer": [0, 1, 2, 3, 4, 5, 6, 7], "floating": [100.0, 101.0, 102.0]}',
) )