├── .gitignore
├── LICENSE
├── MANIFEST.in
├── README.rst
├── pyjs9
├── __init__.py
└── pylintrc
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # scratch files
2 | *~
3 | *.bak
4 | foo*
5 |
6 | # scratch diretories
7 | /test/
8 | /gen/
9 |
10 | # Compiled python modules.
11 | *.pyc
12 |
13 | # Setuptools distribution folder.
14 | /dist/
15 |
16 | # Build directory
17 | /build/
18 |
19 | # Python egg metadata, regenerated from source files by setuptools.
20 | /*.egg-info
21 |
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | JS9 is distributed under the terms of The MIT License (MIT), reproduced below.
2 |
3 | Copyright (c) 2014 Smithsonian Institution
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 | include README.rst
3 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | **My software career comes to an end on July 1, 2022 and with it will end active development of pyjs9. Please plan accordingly. Eric**
2 |
3 | .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.6675877.svg
4 | :target: https://doi.org/10.5281/zenodo.6675877
5 |
6 | JS9 brings image display right into your browser::
7 |
8 | - display URL-based FITS images and binary tables
9 | - drag and drop FITS images and binary tables
10 | - change the colormap and scale
11 | - manipulate the contrast/bias with the mouse
12 | - display pixel values and WCS position information
13 | - create and manipulate geometric regions of interest
14 | - add your own extensions using plugins and the Public API
15 | - perform data analysis (local and server-side)
16 | - display RGB composite images
17 | - control JS9 from the command line
18 | - print images
19 | - much more ...
20 |
21 | See: https://js9.si.edu for more information about JS9.
22 |
23 | pyjs9.py connects Python and JS9 via the js9Helper.js back-end server::
24 |
25 | - The JS9 class constructor connects to a single JS9 instance in a Web page.
26 | - The JS9 object supports the JS9 Public API and a shorter command-line syntax.
27 | - See: https://js9.si.edu/js9/help/publicapi.html for info about the public api
28 | - Send/retrieve numpy arrays and astropy (or pyfits) hdulists to/from JS9.
29 |
30 | Requirements: Python 3.5 or higher is required. Beyond that, pyjs9
31 | communicates with a JS9 back-end Node server (which communicates with
32 | the browser itself). By default, pyjs9 utilizes the `requests
33 | ` module to communicate
34 | with the JS9 back-end server. However, if you install
35 | `python-socketio` `, pyjs9
36 | will use the faster, persistent `socket.io http://socket.io/`
37 | protocol.
38 |
39 | Install from the repository using pip3, as usual::
40 |
41 | > pip3 install git+https://github.com/ericmandel/pyjs9.git#egg=pyjs9
42 |
43 | or from a local copy::
44 |
45 | > pip3 install /path/to/local/copy
46 |
47 | Mandatory dependencies::
48 |
49 | requests
50 |
51 | Optional dependencies::
52 |
53 | numpy # support for GetNumpy and SetNumpy methods
54 | astropy # support for GetFITS and SetFITS methods
55 | python-socketio # fast, persistent socket.io protocol, instead of html
56 | # (install version 5.x, version 4.x is deprecated)
57 |
58 | To run::
59 |
60 | > # ensure JS9 node-server is running ...
61 | > # visit your local JS9 Web page in your browser ...
62 | > python
63 | ... (startup messages) ...
64 | >>> import pyjs9
65 | >>>
66 | >>> j = pyjs9.JS9() # default: connect to 'http://localhost'
67 | >>>
68 | >>> j.GetColormap()
69 | {'bias': 0.5, 'colormap': 'grey', 'contrast': 1}
70 | >>> j.SetColormap('red')
71 | >>> j.cmap()
72 | 'red 1 0.5'
73 | >>>
74 | >>> hdul = j.GetFITS()
75 | >>> hdul.info()
76 | Filename: (No file associated with this HDUList)
77 | No. Name Type Cards Dimensions Format
78 | 0 PRIMARY PrimaryHDU 6 (1024, 1024) int32
79 | >>>
80 | >>> narr = j.GetNumpy()
81 | >>> narr.shape
82 | (1024, 1024)
83 |
84 | If you have internet connectivity, visit the JS9 Web page at
85 | https://js9.si.edu with your browser and::
86 |
87 | > python
88 | ... (startup messages) ...
89 | >>> import pyjs9
90 | >>>
91 | >>> j = pyjs9.JS9('https://js9.si.edu') # connect to JS9 Web site
92 | >>>
93 | >>> j.GetColormap()
94 | {'bias': 0.5, 'colormap': 'grey', 'contrast': 1}
95 | >>>
96 | >>> # etc ...
97 |
--------------------------------------------------------------------------------
/pyjs9/pylintrc:
--------------------------------------------------------------------------------
1 | [MASTER]
2 |
3 | # A comma-separated list of package or module names from where C extensions may
4 | # be loaded. Extensions are loading into the active Python interpreter and may
5 | # run arbitrary code
6 | extension-pkg-whitelist=
7 |
8 | # Add files or directories to the blacklist. They should be base names, not
9 | # paths.
10 | ignore=CVS
11 |
12 | # Add files or directories matching the regex patterns to the blacklist. The
13 | # regex matches against base names, not paths.
14 | ignore-patterns=
15 |
16 | # Python code to execute, usually for sys.path manipulation such as
17 | # pygtk.require().
18 | #init-hook=
19 |
20 | # Use multiple processes to speed up Pylint.
21 | jobs=1
22 |
23 | # List of plugins (as comma separated values of python modules names) to load,
24 | # usually to register additional checkers.
25 | load-plugins=
26 |
27 | # Pickle collected data for later comparisons.
28 | persistent=yes
29 |
30 | # Specify a configuration file.
31 | #rcfile=
32 |
33 | # When enabled, pylint would attempt to guess common misconfiguration and emit
34 | # user-friendly hints instead of false-positive error messages
35 | suggestion-mode=yes
36 |
37 | # Allow loading of arbitrary C extensions. Extensions are imported into the
38 | # active Python interpreter and may run arbitrary code.
39 | unsafe-load-any-extension=no
40 |
41 |
42 | [MESSAGES CONTROL]
43 |
44 | # Only show warnings with the listed confidence levels. Leave empty to show
45 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
46 | confidence=
47 |
48 | # Disable the message, report, category or checker with the given id(s). You
49 | # can either give multiple identifiers separated by comma (,) or put this
50 | # option multiple times (only on the command line, not in the configuration
51 | # file where it should appear only once).You can also use "--disable=all" to
52 | # disable everything first and then reenable specific checks. For example, if
53 | # you want to run only the similarities checker, you can use "--disable=all
54 | # --enable=similarities". If you want to run only the classes checker, but have
55 | # no Warning level messages displayed, use"--disable=all --enable=classes
56 | # --disable=W"
57 | # added by egm
58 | disable=print-statement,
59 | parameter-unpacking,
60 | unpacking-in-except,
61 | old-raise-syntax,
62 | backtick,
63 | long-suffix,
64 | old-ne-operator,
65 | old-octal-literal,
66 | import-star-module-level,
67 | non-ascii-bytes-literal,
68 | invalid-unicode-literal,
69 | raw-checker-failed,
70 | bad-inline-option,
71 | locally-disabled,
72 | locally-enabled,
73 | file-ignored,
74 | suppressed-message,
75 | useless-suppression,
76 | deprecated-pragma,
77 | apply-builtin,
78 | basestring-builtin,
79 | buffer-builtin,
80 | cmp-builtin,
81 | coerce-builtin,
82 | execfile-builtin,
83 | file-builtin,
84 | long-builtin,
85 | raw_input-builtin,
86 | reduce-builtin,
87 | standarderror-builtin,
88 | unicode-builtin,
89 | xrange-builtin,
90 | coerce-method,
91 | delslice-method,
92 | getslice-method,
93 | setslice-method,
94 | no-absolute-import,
95 | old-division,
96 | dict-iter-method,
97 | dict-view-method,
98 | next-method-called,
99 | metaclass-assignment,
100 | indexing-exception,
101 | raising-string,
102 | reload-builtin,
103 | oct-method,
104 | hex-method,
105 | nonzero-method,
106 | cmp-method,
107 | input-builtin,
108 | round-builtin,
109 | intern-builtin,
110 | unichr-builtin,
111 | map-builtin-not-iterating,
112 | zip-builtin-not-iterating,
113 | range-builtin-not-iterating,
114 | filter-builtin-not-iterating,
115 | using-cmp-argument,
116 | eq-without-hash,
117 | div-method,
118 | idiv-method,
119 | rdiv-method,
120 | exception-message-attribute,
121 | invalid-str-codec,
122 | sys-max-int,
123 | bad-python3-import,
124 | deprecated-string-function,
125 | deprecated-str-translate-call,
126 | deprecated-itertools-function,
127 | deprecated-types-field,
128 | next-method-defined,
129 | dict-items-not-iterating,
130 | dict-keys-not-iterating,
131 | dict-values-not-iterating,
132 | deprecated-operator-function,
133 | deprecated-urllib-function,
134 | xreadlines-attribute,
135 | deprecated-sys-function,
136 | exception-escape,
137 | comprehension-escape,
138 | fixme,
139 | invalid-name,
140 | too-many-public-methods,
141 | too-many-lines
142 |
143 | # Enable the message, report, category or checker with the given id(s). You can
144 | # either give multiple identifier separated by comma (,) or put this option
145 | # multiple time (only on the command line, not in the configuration file where
146 | # it should appear only once). See also the "--disable" option for examples.
147 | enable=c-extension-no-member
148 |
149 |
150 | [REPORTS]
151 |
152 | # Python expression which should return a note less than 10 (10 is the highest
153 | # note). You have access to the variables errors warning, statement which
154 | # respectively contain the number of errors / warnings messages and the total
155 | # number of statements analyzed. This is used by the global evaluation report
156 | # (RP0004).
157 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
158 |
159 | # Template used to display messages. This is a python new-style format string
160 | # used to format the message information. See doc for all details
161 | #msg-template=
162 |
163 | # Set the output format. Available formats are text, parseable, colorized, json
164 | # and msvs (visual studio).You can also give a reporter class, eg
165 | # mypackage.mymodule.MyReporterClass.
166 | output-format=text
167 |
168 | # Tells whether to display a full report or only the messages
169 | reports=no
170 |
171 | # Activate the evaluation score.
172 | score=yes
173 |
174 |
175 | [REFACTORING]
176 |
177 | # Maximum number of nested blocks for function / method body
178 | max-nested-blocks=5
179 |
180 | # Complete name of functions that never returns. When checking for
181 | # inconsistent-return-statements if a never returning function is called then
182 | # it will be considered as an explicit return statement and no message will be
183 | # printed.
184 | never-returning-functions=optparse.Values,sys.exit
185 |
186 |
187 | [LOGGING]
188 |
189 | # Logging modules to check that the string format arguments are in logging
190 | # function parameter format
191 | logging-modules=logging
192 |
193 |
194 | [SPELLING]
195 |
196 | # Limits count of emitted suggestions for spelling mistakes
197 | max-spelling-suggestions=4
198 |
199 | # Spelling dictionary name. Available dictionaries: none. To make it working
200 | # install python-enchant package.
201 | spelling-dict=
202 |
203 | # List of comma separated words that should not be checked.
204 | spelling-ignore-words=
205 |
206 | # A path to a file that contains private dictionary; one word per line.
207 | spelling-private-dict-file=
208 |
209 | # Tells whether to store unknown words to indicated private dictionary in
210 | # --spelling-private-dict-file option instead of raising a message.
211 | spelling-store-unknown-words=no
212 |
213 |
214 | [MISCELLANEOUS]
215 |
216 | # List of note tags to take in consideration, separated by a comma.
217 | notes=FIXME,
218 | XXX,
219 | TODO
220 |
221 |
222 | [SIMILARITIES]
223 |
224 | # Ignore comments when computing similarities.
225 | ignore-comments=yes
226 |
227 | # Ignore docstrings when computing similarities.
228 | ignore-docstrings=yes
229 |
230 | # Ignore imports when computing similarities.
231 | ignore-imports=no
232 |
233 | # Minimum lines number of a similarity.
234 | min-similarity-lines=4
235 |
236 |
237 | [TYPECHECK]
238 |
239 | # List of decorators that produce context managers, such as
240 | # contextlib.contextmanager. Add to this list to register other decorators that
241 | # produce valid context managers.
242 | contextmanager-decorators=contextlib.contextmanager
243 |
244 | # List of members which are set dynamically and missed by pylint inference
245 | # system, and so shouldn't trigger E1101 when accessed. Python regular
246 | # expressions are accepted.
247 | generated-members=
248 |
249 | # Tells whether missing members accessed in mixin class should be ignored. A
250 | # mixin class is detected if its name ends with "mixin" (case insensitive).
251 | ignore-mixin-members=yes
252 |
253 | # This flag controls whether pylint should warn about no-member and similar
254 | # checks whenever an opaque object is returned when inferring. The inference
255 | # can return multiple potential results while evaluating a Python object, but
256 | # some branches might not be evaluated, which results in partial inference. In
257 | # that case, it might be useful to still emit no-member and other checks for
258 | # the rest of the inferred objects.
259 | ignore-on-opaque-inference=yes
260 |
261 | # List of class names for which member attributes should not be checked (useful
262 | # for classes with dynamically set attributes). This supports the use of
263 | # qualified names.
264 | ignored-classes=optparse.Values,thread._local,_thread._local
265 |
266 | # List of module names for which member attributes should not be checked
267 | # (useful for modules/projects where namespaces are manipulated during runtime
268 | # and thus existing member attributes cannot be deduced by static analysis. It
269 | # supports qualified module names, as well as Unix pattern matching.
270 | ignored-modules=
271 |
272 | # Show a hint with possible names when a member name was not found. The aspect
273 | # of finding the hint is based on edit distance.
274 | missing-member-hint=yes
275 |
276 | # The minimum edit distance a name should have in order to be considered a
277 | # similar match for a missing member name.
278 | missing-member-hint-distance=1
279 |
280 | # The total number of similar names that should be taken in consideration when
281 | # showing a hint for a missing member.
282 | missing-member-max-choices=1
283 |
284 |
285 | [VARIABLES]
286 |
287 | # List of additional names supposed to be defined in builtins. Remember that
288 | # you should avoid to define new builtins when possible.
289 | additional-builtins=
290 |
291 | # Tells whether unused global variables should be treated as a violation.
292 | allow-global-unused-variables=yes
293 |
294 | # List of strings which can identify a callback function by name. A callback
295 | # name must start or end with one of those strings.
296 | callbacks=cb_,
297 | _cb
298 |
299 | # A regular expression matching the name of dummy variables (i.e. expectedly
300 | # not used).
301 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
302 |
303 | # Argument names that match this expression will be ignored. Default to name
304 | # with leading underscore
305 | ignored-argument-names=_.*|^ignored_|^unused_
306 |
307 | # Tells whether we should check for unused import in __init__ files.
308 | init-import=no
309 |
310 | # List of qualified module names which can have objects that can redefine
311 | # builtins.
312 | redefining-builtins-modules=six.moves,past.builtins,future.builtins,io,builtins
313 |
314 |
315 | [FORMAT]
316 |
317 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
318 | expected-line-ending-format=
319 |
320 | # Regexp for a line that is allowed to be longer than the limit.
321 | ignore-long-lines=^\s*(# )??$
322 |
323 | # Number of spaces of indent required inside a hanging or continued line.
324 | indent-after-paren=4
325 |
326 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
327 | # tab).
328 | indent-string=' '
329 |
330 | # Maximum number of characters on a single line.
331 | max-line-length=100
332 |
333 | # Maximum number of lines in a module
334 | max-module-lines=1000
335 |
336 | # List of optional constructs for which whitespace checking is disabled. `dict-
337 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
338 | # `trailing-comma` allows a space between comma and closing bracket: (a, ).
339 | # `empty-line` allows space-only lines.
340 | no-space-check=trailing-comma,
341 | dict-separator
342 |
343 | # Allow the body of a class to be on the same line as the declaration if body
344 | # contains single statement.
345 | single-line-class-stmt=no
346 |
347 | # Allow the body of an if to be on the same line as the test if there is no
348 | # else.
349 | single-line-if-stmt=no
350 |
351 |
352 | [BASIC]
353 |
354 | # Naming style matching correct argument names
355 | argument-naming-style=snake_case
356 |
357 | # Regular expression matching correct argument names. Overrides argument-
358 | # naming-style
359 | #argument-rgx=
360 |
361 | # Naming style matching correct attribute names
362 | attr-naming-style=snake_case
363 |
364 | # Regular expression matching correct attribute names. Overrides attr-naming-
365 | # style
366 | #attr-rgx=
367 |
368 | # Bad variable names which should always be refused, separated by a comma
369 | bad-names=foo,
370 | bar,
371 | baz,
372 | toto,
373 | tutu,
374 | tata
375 |
376 | # Naming style matching correct class attribute names
377 | class-attribute-naming-style=any
378 |
379 | # Regular expression matching correct class attribute names. Overrides class-
380 | # attribute-naming-style
381 | #class-attribute-rgx=
382 |
383 | # Naming style matching correct class names
384 | class-naming-style=PascalCase
385 |
386 | # Regular expression matching correct class names. Overrides class-naming-style
387 | #class-rgx=
388 |
389 | # Naming style matching correct constant names
390 | const-naming-style=UPPER_CASE
391 |
392 | # Regular expression matching correct constant names. Overrides const-naming-
393 | # style
394 | #const-rgx=
395 |
396 | # Minimum line length for functions/classes that require docstrings, shorter
397 | # ones are exempt.
398 | docstring-min-length=-1
399 |
400 | # Naming style matching correct function names
401 | function-naming-style=snake_case
402 |
403 | # Regular expression matching correct function names. Overrides function-
404 | # naming-style
405 | #function-rgx=
406 |
407 | # Good variable names which should always be accepted, separated by a comma
408 | good-names=i,
409 | j,
410 | k,
411 | ex,
412 | Run,
413 | _
414 |
415 | # Include a hint for the correct naming format with invalid-name
416 | include-naming-hint=no
417 |
418 | # Naming style matching correct inline iteration names
419 | inlinevar-naming-style=any
420 |
421 | # Regular expression matching correct inline iteration names. Overrides
422 | # inlinevar-naming-style
423 | #inlinevar-rgx=
424 |
425 | # Naming style matching correct method names
426 | method-naming-style=snake_case
427 |
428 | # Regular expression matching correct method names. Overrides method-naming-
429 | # style
430 | #method-rgx=
431 |
432 | # Naming style matching correct module names
433 | module-naming-style=snake_case
434 |
435 | # Regular expression matching correct module names. Overrides module-naming-
436 | # style
437 | #module-rgx=
438 |
439 | # Colon-delimited sets of names that determine each other's naming style when
440 | # the name regexes allow several styles.
441 | name-group=
442 |
443 | # Regular expression which should only match function or class names that do
444 | # not require a docstring.
445 | no-docstring-rgx=^_
446 |
447 | # List of decorators that produce properties, such as abc.abstractproperty. Add
448 | # to this list to register other decorators that produce valid properties.
449 | property-classes=abc.abstractproperty
450 |
451 | # Naming style matching correct variable names
452 | variable-naming-style=snake_case
453 |
454 | # Regular expression matching correct variable names. Overrides variable-
455 | # naming-style
456 | #variable-rgx=
457 |
458 |
459 | [DESIGN]
460 |
461 | # Maximum number of arguments for function / method
462 | max-args=5
463 |
464 | # Maximum number of attributes for a class (see R0902).
465 | max-attributes=7
466 |
467 | # Maximum number of boolean expressions in a if statement
468 | max-bool-expr=5
469 |
470 | # Maximum number of branch for function / method body
471 | max-branches=12
472 |
473 | # Maximum number of locals for function / method body
474 | max-locals=15
475 |
476 | # Maximum number of parents for a class (see R0901).
477 | max-parents=7
478 |
479 | # Maximum number of public methods for a class (see R0904).
480 | max-public-methods=20
481 |
482 | # Maximum number of return / yield for function / method body
483 | max-returns=6
484 |
485 | # Maximum number of statements in function / method body
486 | max-statements=50
487 |
488 | # Minimum number of public methods for a class (see R0903).
489 | min-public-methods=2
490 |
491 |
492 | [CLASSES]
493 |
494 | # List of method names used to declare (i.e. assign) instance attributes.
495 | defining-attr-methods=__init__,
496 | __new__,
497 | setUp
498 |
499 | # List of member names, which should be excluded from the protected access
500 | # warning.
501 | exclude-protected=_asdict,
502 | _fields,
503 | _replace,
504 | _source,
505 | _make
506 |
507 | # List of valid names for the first argument in a class method.
508 | valid-classmethod-first-arg=cls
509 |
510 | # List of valid names for the first argument in a metaclass class method.
511 | valid-metaclass-classmethod-first-arg=mcs
512 |
513 |
514 | [IMPORTS]
515 |
516 | # Allow wildcard imports from modules that define __all__.
517 | allow-wildcard-with-all=no
518 |
519 | # Analyse import fallback blocks. This can be used to support both Python 2 and
520 | # 3 compatible code, which means that the block might have code that exists
521 | # only in one or another interpreter, leading to false positives when analysed.
522 | analyse-fallback-blocks=no
523 |
524 | # Deprecated modules which should not be used, separated by a comma
525 | deprecated-modules=regsub,
526 | TERMIOS,
527 | Bastion,
528 | rexec
529 |
530 | # Create a graph of external dependencies in the given file (report RP0402 must
531 | # not be disabled)
532 | ext-import-graph=
533 |
534 | # Create a graph of every (i.e. internal and external) dependencies in the
535 | # given file (report RP0402 must not be disabled)
536 | import-graph=
537 |
538 | # Create a graph of internal dependencies in the given file (report RP0402 must
539 | # not be disabled)
540 | int-import-graph=
541 |
542 | # Force import order to recognize a module as part of the standard
543 | # compatibility libraries.
544 | known-standard-library=
545 |
546 | # Force import order to recognize a module as part of a third party library.
547 | known-third-party=enchant
548 |
549 |
550 | [EXCEPTIONS]
551 |
552 | # Exceptions that will emit a warning when being caught. Defaults to
553 | # "Exception"
554 | overgeneral-exceptions=Exception
555 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | def readme():
4 | with open('README.rst') as f:
5 | return f.read()
6 |
7 | setup(name='pyjs9',
8 | version='3.8',
9 | description='Python/JS9 connection, with numpy and astropy/fits support',
10 | long_description=readme(),
11 | author='Eric Mandel',
12 | author_email='saord@cfa.harvard.edu',
13 | classifiers=[
14 | 'Development Status :: 5 - Production/Stable',
15 | 'License :: OSI Approved :: MIT License',
16 | 'Programming Language :: Python :: 3',
17 | 'Topic :: Scientific/Engineering :: Astronomy',
18 | ],
19 | keywords='astronomy astrophysics image display',
20 | url='https://js9.si.edu',
21 | license='MIT',
22 | packages=['pyjs9'],
23 | install_requires=['requests'],
24 | extras_require={'all': ['numpy', 'astropy']},
25 | zip_safe=False)
26 |
--------------------------------------------------------------------------------