├── .github └── workflows │ └── build.yml ├── .gitignore ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── lib ├── npy.rb └── npy │ ├── file.rb │ └── version.rb ├── npy.gemspec └── test ├── load_test.rb ├── save_test.rb ├── support ├── create.py ├── multiple.npz ├── rank0.npy ├── single.npy ├── types │ ├── bool.npy │ ├── complex128.npy │ ├── complex64.npy │ ├── float16.npy │ ├── float32.npy │ ├── float64.npy │ ├── int16.npy │ ├── int32.npy │ ├── int64.npy │ ├── int8.npy │ ├── uint16.npy │ ├── uint32.npy │ ├── uint64.npy │ └── uint8.npy └── verify.py ├── test_helper.rb └── types_test.rb /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v4 8 | - uses: ruby/setup-ruby@v1 9 | with: 10 | ruby-version: 3.4 11 | bundler-cache: true 12 | - run: bundle exec rake test 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | *.lock 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.4.0 (2024-10-23) 2 | 3 | - Dropped support for Ruby < 3.1 4 | 5 | ## 0.3.0 (2022-09-27) 6 | 7 | - Dropped support for Ruby < 2.7 8 | 9 | ## 0.2.0 (2019-10-27) 10 | 11 | - Added support for loading `bool` type (as `uint8` for now) 12 | - Return `NArray` object for rank-0 arrays 13 | 14 | ## 0.1.2 (2019-09-15) 15 | 16 | - Added support for saving and loading IO objects 17 | - Added `load_npz_string` 18 | - Fixed bug with rank-1 arrays 19 | 20 | ## 0.1.1 (2019-09-14) 21 | 22 | - Added support for saving files 23 | - Added support for npy version 2.0 and 3.0 24 | - Fixed error with empty shapes 25 | 26 | ## 0.1.0 (2019-09-12) 27 | 28 | - First release 29 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | 5 | gem "rake" 6 | gem "minitest" 7 | gem "benchmark-ips", require: false 8 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-2025 Andrew Kane 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Npy 2 | 3 | Save and load NumPy `npy` and `npz` files in Ruby - no Python required 4 | 5 | :fire: Uses [Numo](https://github.com/ruby-numo/numo-narray) for blazing performance 6 | 7 | [![Build Status](https://github.com/ankane/npy/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/npy/actions) 8 | 9 | ## Installation 10 | 11 | Add this line to your application’s Gemfile: 12 | 13 | ```ruby 14 | gem "npy" 15 | ``` 16 | 17 | ## Getting Started 18 | 19 | ### npy 20 | 21 | `npy` files contain a single array 22 | 23 | Save an array 24 | 25 | ```ruby 26 | x = Numo::Int32[0..9] 27 | Npy.save("x.npy", x) 28 | ``` 29 | 30 | Load an `npy` file 31 | 32 | ```ruby 33 | x = Npy.load("x.npy") 34 | ``` 35 | 36 | Load an `npy` string 37 | 38 | ```ruby 39 | byte_str = File.binread("x.npy") 40 | x = Npy.load_string(byte_str) 41 | ``` 42 | 43 | ### npz 44 | 45 | `npz` files contain multiple arrays 46 | 47 | Save multiple arrays 48 | 49 | ```ruby 50 | x = Numo::Int32[0..9] 51 | y = x * 2 52 | Npy.save_npz("data.npz", x: x, y: y) 53 | ``` 54 | 55 | Load an `npz` file 56 | 57 | ```ruby 58 | data = Npy.load_npz("data.npz") 59 | ``` 60 | 61 | Get keys 62 | 63 | ```ruby 64 | data.keys 65 | ``` 66 | 67 | Get an array 68 | 69 | ```ruby 70 | data["x"] 71 | ``` 72 | 73 | Arrays are lazy loaded for performance 74 | 75 | ## Resources 76 | 77 | - [npy format](https://docs.scipy.org/doc/numpy/reference/generated/numpy.lib.format.html#module-numpy.lib.format) 78 | - [NumPy data types](https://docs.scipy.org/doc/numpy/user/basics.types.html) 79 | - [Numo::NArray docs](https://ruby-numo.github.io/narray/narray/Numo/NArray.html) 80 | 81 | ## History 82 | 83 | View the [changelog](https://github.com/ankane/npy/blob/master/CHANGELOG.md) 84 | 85 | ## Contributing 86 | 87 | Everyone is encouraged to help improve this project. Here are a few ways you can help: 88 | 89 | - [Report bugs](https://github.com/ankane/npy/issues) 90 | - Fix bugs and [submit pull requests](https://github.com/ankane/npy/pulls) 91 | - Write, clarify, or fix documentation 92 | - Suggest or add new features 93 | 94 | To get started with development: 95 | 96 | ```sh 97 | git clone https://github.com/ankane/npy.git 98 | cd npy 99 | bundle install 100 | bundle exec rake test 101 | ``` 102 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | task default: :test 5 | Rake::TestTask.new do |t| 6 | t.libs << "test" 7 | t.pattern = "test/**/*_test.rb" 8 | end 9 | 10 | task :benchmark do 11 | require "benchmark/ips" 12 | require "numo/narray" 13 | require "npy" 14 | 15 | x = Numo::Int32[1..1_000_000] 16 | 17 | tempdir = File.dirname(Tempfile.new("npy")) 18 | 19 | File.binwrite("#{tempdir}/x.dump", Marshal.dump(x)) 20 | Npy.save("#{tempdir}/x.npy", x) 21 | 22 | x1 = Marshal.load(File.binread("#{tempdir}/x.dump")) 23 | x2 = Npy.load("#{tempdir}/x.npy") 24 | 25 | raise "Mismatch: x1" unless x1 == x 26 | raise "Mismatch: x2" unless x2 == x 27 | 28 | Benchmark.ips do |bx| 29 | bx.report("numo") { Marshal.load(File.binread("#{tempdir}/x.dump")) } 30 | bx.report("npy") { Npy.load("#{tempdir}/x.npy") } 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/npy.rb: -------------------------------------------------------------------------------- 1 | # dependencies 2 | require "numo/narray" 3 | require "zip" 4 | 5 | # stdlib 6 | require "stringio" 7 | require "tempfile" 8 | 9 | # modules 10 | require_relative "npy/file" 11 | require_relative "npy/version" 12 | 13 | module Npy 14 | class Error < StandardError; end 15 | 16 | MAGIC_STR = "\x93NUMPY".b 17 | 18 | TYPE_MAP = { 19 | "|i1" => Numo::Int8, 20 | " Numo::Int16, 21 | " Numo::Int32, 22 | " Numo::Int64, 23 | "|u1" => Numo::UInt8, 24 | " Numo::UInt16, 25 | " Numo::UInt32, 26 | " Numo::UInt64, 27 | " Numo::SFloat, 28 | " Numo::DFloat, 29 | " Numo::SComplex, 30 | " Numo::DComplex, 31 | # must come last 32 | # as save uses first match 33 | "|b1" => Numo::UInt8 34 | } 35 | 36 | class << self 37 | def load(path) 38 | case path 39 | when IO, StringIO 40 | load_io(path) 41 | else 42 | load_file(path) 43 | end 44 | end 45 | 46 | def load_npz(path) 47 | case path 48 | when IO, StringIO 49 | load_npz_io(path) 50 | else 51 | load_npz_file(path) 52 | end 53 | end 54 | 55 | def load_string(byte_str) 56 | load_io(StringIO.new(byte_str)) 57 | end 58 | 59 | def load_npz_string(byte_str) 60 | # not playing nicely with StringIO 61 | file = Tempfile.new("npy") 62 | begin 63 | file.write(byte_str) 64 | load_npz_io(file) 65 | ensure 66 | file.close 67 | file.unlink 68 | end 69 | end 70 | 71 | # TODO make private 72 | def load_io(io) 73 | magic = io.read(6) 74 | raise Error, "Invalid npy format" unless magic&.b == MAGIC_STR 75 | 76 | version = io.read(2) 77 | 78 | header_len = 79 | case version 80 | when "\x01\x00".b 81 | io.read(2).unpack1("S<") 82 | when "\x02\x00".b, "\x03\x00".b 83 | io.read(4).unpack1("I<") 84 | else 85 | raise Error, "Unsupported version" 86 | end 87 | header = io.read(header_len) 88 | descr, fortran_order, shape = parse_header(header) 89 | raise Error, "Fortran order not supported" if fortran_order 90 | 91 | klass = TYPE_MAP[descr] 92 | raise Error, "Type not supported: #{descr}" unless klass 93 | 94 | # use from_string instead of from_binary for max compatibility 95 | # from_binary introduced in 0.9.0.4 96 | # numo from_string can't handle rank0 97 | if shape.empty? 98 | klass.cast(klass.from_string(io.read, [1])[0]) 99 | else 100 | klass.from_string(io.read, shape) 101 | end 102 | end 103 | 104 | # TODO make private 105 | def load_npz_io(io) 106 | File.new(io) 107 | end 108 | 109 | def save(path, arr) 110 | case path 111 | when IO, StringIO 112 | save_io(path, arr) 113 | else 114 | save_file(path, arr) 115 | end 116 | true 117 | end 118 | 119 | def save_npz(path, arrs) 120 | case path 121 | when IO, StringIO 122 | save_npz_io(path, arrs) 123 | else 124 | save_npz_file(path, arrs) 125 | end 126 | true 127 | end 128 | 129 | private 130 | 131 | def load_file(path) 132 | with_file(path, "rb") do |f| 133 | load_io(f) 134 | end 135 | end 136 | 137 | def load_npz_file(path) 138 | with_file(path, "rb") do |f| 139 | load_npz_io(f) 140 | end 141 | end 142 | 143 | def save_file(path, arr) 144 | with_file(path, "wb") do |f| 145 | save_io(f, arr) 146 | end 147 | end 148 | 149 | def save_io(f, arr) 150 | unless arr.is_a?(Numo::NArray) 151 | begin 152 | arr = Numo::NArray.cast(arr) 153 | rescue TypeError 154 | # do nothing 155 | end 156 | end 157 | 158 | # desc 159 | descr = TYPE_MAP.find { |_, v| arr.is_a?(v) } 160 | raise Error, "Unsupported type: #{arr.class.name}" unless descr 161 | 162 | # shape 163 | shape = arr.shape 164 | 165 | # header 166 | header = "{'descr': '#{descr[0]}', 'fortran_order': False, 'shape': (#{shape.join(", ")}#{shape.size == 1 ? "," : nil}), }".b 167 | padding_len = 64 - (11 + header.length) % 64 168 | padding = "\x20".b * padding_len 169 | header = "#{header}#{padding}\n" 170 | 171 | f.write(MAGIC_STR) 172 | f.write("\x01\x00".b) 173 | f.write([header.bytesize].pack("S<")) 174 | f.write(header) 175 | f.write(arr.to_string) 176 | end 177 | 178 | def save_npz_file(path, arrs) 179 | with_file(path, "wb") do |f| 180 | save_npz_io(f, arrs) 181 | end 182 | end 183 | 184 | def save_npz_io(f, arrs) 185 | Zip::File.open(f, create: true) do |zipfile| 186 | arrs.each do |k, v| 187 | zipfile.get_output_stream("#{k}.npy") do |f2| 188 | save_io(f2, v) 189 | end 190 | end 191 | end 192 | end 193 | 194 | def with_file(path, mode) 195 | ::File.open(path, mode) do |f| 196 | yield f 197 | end 198 | end 199 | 200 | # header is Python dict, so use regex to parse 201 | def parse_header(header) 202 | # sanity check 203 | raise Error, "Bad header" if !header || header[-1] != "\n" 204 | 205 | # descr 206 | m = /'descr': *'([^']+)'/.match(header) 207 | descr = m[1] 208 | 209 | # fortran_order 210 | m = /'fortran_order': *([^,]+)/.match(header) 211 | fortran_order = m[1] == "True" 212 | 213 | # shape 214 | m = /'shape': *\(([^)]*)\)/.match(header) 215 | # no space in split for max compatibility 216 | shape = m[1].strip.split(",").map(&:to_i) 217 | 218 | [descr, fortran_order, shape] 219 | end 220 | end 221 | end 222 | -------------------------------------------------------------------------------- /lib/npy/file.rb: -------------------------------------------------------------------------------- 1 | module Npy 2 | class File 3 | def initialize(io) 4 | @streams = {} 5 | Zip::File.open_buffer(io) do |zipfile| 6 | zipfile.each do |entry| 7 | name = entry.name.delete_suffix(".npy") 8 | @streams[name] = entry.get_input_stream 9 | end 10 | end 11 | @data = {} 12 | end 13 | 14 | def keys 15 | @streams.keys 16 | end 17 | 18 | def [](name) 19 | @data[name] ||= Npy.load_io(@streams[name]) if @streams[name] 20 | end 21 | 22 | def to_h 23 | keys.map { |k| [k, self[k]] }.to_h 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/npy/version.rb: -------------------------------------------------------------------------------- 1 | module Npy 2 | VERSION = "0.4.0" 3 | end 4 | -------------------------------------------------------------------------------- /npy.gemspec: -------------------------------------------------------------------------------- 1 | require_relative "lib/npy/version" 2 | 3 | Gem::Specification.new do |spec| 4 | spec.name = "npy" 5 | spec.version = Npy::VERSION 6 | spec.summary = "Save and load NumPy npy and npz files in Ruby" 7 | spec.homepage = "https://github.com/ankane/npy" 8 | spec.license = "MIT" 9 | 10 | spec.author = "Andrew Kane" 11 | spec.email = "andrew@ankane.org" 12 | 13 | spec.files = Dir["*.{md,txt}", "{lib}/**/*"] 14 | spec.require_path = "lib" 15 | 16 | spec.required_ruby_version = ">= 3.1" 17 | 18 | spec.add_dependency "numo-narray" 19 | spec.add_dependency "rubyzip", ">= 2.4.1" 20 | end 21 | -------------------------------------------------------------------------------- /test/load_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class LoadTest < Minitest::Test 4 | def test_load_npy_file 5 | act = Npy.load("test/support/single.npy") 6 | assert_array Numo::Int64[0...10], act 7 | end 8 | 9 | def test_load_npz_file 10 | data = Npy.load_npz("test/support/multiple.npz") 11 | assert_equal ["x", "y"], data.keys 12 | assert_array Numo::Int64[0...10], data["x"] 13 | assert_array Numo::Int64[0...10] * 2, data["y"] 14 | assert_equal ["x", "y"], data.to_h.keys 15 | assert_nil data["z"] 16 | end 17 | 18 | def test_load_npy_string 19 | byte_str = File.binread("test/support/single.npy") 20 | act = Npy.load_string(byte_str) 21 | assert_array Numo::Int64[0...10], act 22 | end 23 | 24 | def test_rank0 25 | act = Npy.load("test/support/rank0.npy") 26 | assert_equal 0, act.rank 27 | assert_array Numo::Int64.cast(1), act 28 | end 29 | 30 | # this test fails when recreating multiple.npz 31 | # rubyzip 3.0.0.alpha fixes it 32 | def test_load_npz_string 33 | byte_str = File.binread("test/support/multiple.npz") 34 | data = Npy.load_npz_string(byte_str) 35 | assert_equal ["x", "y"], data.keys 36 | assert_array Numo::Int64[0...10], data["x"] 37 | assert_array Numo::Int64[0...10] * 2, data["y"] 38 | assert_equal ["x", "y"], data.to_h.keys 39 | assert_nil data["z"] 40 | end 41 | 42 | def test_invalid_format 43 | error = assert_raises Npy::Error do 44 | Npy.load_string("hi") 45 | end 46 | assert_equal "Invalid npy format", error.message 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /test/save_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class SaveTest < Minitest::Test 4 | def test_save_npy 5 | arr = Numo::Int64.cast([[1, 2, 3], [4, 5, 6]]) 6 | Npy.save(tempfile, arr) 7 | assert_array arr, Npy.load(tempfile) 8 | # Npy.save("test/support/generated.npy", arr) 9 | end 10 | 11 | def test_save_npy_array 12 | arr = Numo::NArray.cast([[1, 2, 3], [4, 5, 6]]) 13 | Npy.save(tempfile, arr.to_a) 14 | assert_array arr, Npy.load(tempfile) 15 | # Npy.save("test/support/generated_array.npy", arr) 16 | end 17 | 18 | # make sure no conflict with bool 19 | # need to check output in verify.py 20 | def test_save_npy_uint8 21 | arr = Numo::UInt8.cast([[1, 2, 3], [4, 5, 6]]) 22 | Npy.save(tempfile, arr) 23 | assert_array arr, Npy.load(tempfile) 24 | # Npy.save("test/support/generated_uint8.npy", arr) 25 | end 26 | 27 | def test_save_npy_rank0 28 | arr = 1 29 | Npy.save(tempfile, arr) 30 | assert_equal arr, Npy.load(tempfile) 31 | # Npy.save("test/support/generated_rank0.npy", arr) 32 | end 33 | 34 | def test_save_npy_bad_type 35 | arr = "hello" 36 | error = assert_raises Npy::Error do 37 | Npy.save(tempfile, arr) 38 | end 39 | assert_equal "Unsupported type: String", error.message 40 | end 41 | 42 | def test_save_npy_float64 43 | arr = Numo::DFloat.cast([[1, 2, 3], [4, 5, 6]]) 44 | Npy.save(tempfile, arr) 45 | assert_array arr, Npy.load(tempfile) 46 | end 47 | 48 | def test_save_npy_1d 49 | arr = Numo::Int64.cast([1, 2, 3, 4, 5, 6]) 50 | Npy.save(tempfile, arr) 51 | assert_array arr, Npy.load(tempfile) 52 | # Npy.save("test/support/generated_1d.npy", arr) 53 | end 54 | 55 | def test_save_npy_string 56 | io = StringIO.new 57 | arr = Numo::Int64.cast([[1, 2, 3], [4, 5, 6]]) 58 | Npy.save(io, arr) 59 | assert_array arr, Npy.load_string(io.string) 60 | io.rewind 61 | assert_array arr, Npy.load(io) 62 | end 63 | 64 | def test_save_npz 65 | x = Numo::Int64.cast([[1, 2, 3], [4, 5, 6]]) 66 | y = x * 2 67 | Npy.save_npz(tempfile, x: x, y: y) 68 | data = Npy.load_npz(tempfile) 69 | assert_equal ["x", "y"], data.keys 70 | assert_array x, data["x"] 71 | assert_array y, data["y"] 72 | # Npy.save_npz("test/support/generated.npz", x: x, y: y) 73 | end 74 | 75 | def test_save_npz_overwrites 76 | x = Numo::Int64.cast([[1, 2, 3], [4, 5, 6]]) 77 | Npy.save_npz(tempfile, x: x) 78 | Npy.save_npz(tempfile, x2: x) 79 | data = Npy.load_npz(tempfile) 80 | assert_equal ["x2"], data.keys 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /test/support/create.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | x = np.arange(10) 4 | y = x * 2 5 | 6 | np.save("test/support/single.npy", x) 7 | np.save("test/support/rank0.npy", np.array(1)) 8 | np.savez("test/support/multiple.npz", x=x, y=y) 9 | 10 | x2 = np.load("test/support/single.npy") 11 | print(x2) 12 | 13 | data = np.load("test/support/multiple.npz") 14 | print([str(k) for k in data.keys()]) 15 | print(data["x"]) 16 | print(data["y"]) 17 | 18 | types = [ 19 | "int8", "int16", "int32", "int64", 20 | "uint8", "uint16", "uint32", "uint64", 21 | "float16", "float32", "float64", 22 | "complex64", "complex128", "bool" 23 | ] 24 | for t in types: 25 | path = "test/support/types/" + t + ".npy" 26 | np.save(path, x.astype(t)) 27 | print(np.load(path).dtype) 28 | -------------------------------------------------------------------------------- /test/support/multiple.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/multiple.npz -------------------------------------------------------------------------------- /test/support/rank0.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/rank0.npy -------------------------------------------------------------------------------- /test/support/single.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/single.npy -------------------------------------------------------------------------------- /test/support/types/bool.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/bool.npy -------------------------------------------------------------------------------- /test/support/types/complex128.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/complex128.npy -------------------------------------------------------------------------------- /test/support/types/complex64.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/complex64.npy -------------------------------------------------------------------------------- /test/support/types/float16.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/float16.npy -------------------------------------------------------------------------------- /test/support/types/float32.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/float32.npy -------------------------------------------------------------------------------- /test/support/types/float64.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/float64.npy -------------------------------------------------------------------------------- /test/support/types/int16.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/int16.npy -------------------------------------------------------------------------------- /test/support/types/int32.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/int32.npy -------------------------------------------------------------------------------- /test/support/types/int64.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/int64.npy -------------------------------------------------------------------------------- /test/support/types/int8.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/int8.npy -------------------------------------------------------------------------------- /test/support/types/uint16.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/uint16.npy -------------------------------------------------------------------------------- /test/support/types/uint32.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/uint32.npy -------------------------------------------------------------------------------- /test/support/types/uint64.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/uint64.npy -------------------------------------------------------------------------------- /test/support/types/uint8.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankane/npy/ce39032262225bf487d9c23e093687ee09a34af1/test/support/types/uint8.npy -------------------------------------------------------------------------------- /test/support/verify.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | arr = np.load("test/support/generated.npy") 4 | arrs = np.load("test/support/generated.npz") 5 | rank0 = np.load("test/support/generated_rank0.npy") 6 | 7 | print(arr) 8 | print(arrs["x"]) 9 | print(arrs["y"]) 10 | print(rank0) 11 | print(rank0.shape) 12 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | Bundler.require(:default) 3 | require "minitest/autorun" 4 | require "minitest/pride" 5 | 6 | class Minitest::Test 7 | private 8 | 9 | def assert_array(exp, act) 10 | assert_equal exp, act 11 | assert_equal exp.class, act.class 12 | end 13 | 14 | def teardown 15 | @tempfile = nil 16 | end 17 | 18 | def tempfile 19 | @tempfile ||= "#{tempdir}/#{Time.now.to_f}" 20 | end 21 | 22 | def tempdir 23 | @tempdir ||= File.dirname(Tempfile.new("npy")) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /test/types_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class TypesTest < Minitest::Test 4 | def test_int8 5 | act = Npy.load("test/support/types/int8.npy") 6 | assert_array Numo::Int8[0...10], act 7 | end 8 | 9 | def test_int16 10 | act = Npy.load("test/support/types/int16.npy") 11 | assert_array Numo::Int16[0...10], act 12 | end 13 | 14 | def test_int32 15 | act = Npy.load("test/support/types/int32.npy") 16 | assert_array Numo::Int32[0...10], act 17 | end 18 | 19 | def test_int64 20 | act = Npy.load("test/support/types/int64.npy") 21 | assert_array Numo::Int64[0...10], act 22 | end 23 | 24 | def test_uint8 25 | act = Npy.load("test/support/types/uint8.npy") 26 | assert_array Numo::UInt8[0...10], act 27 | end 28 | 29 | def test_uint16 30 | act = Npy.load("test/support/types/uint16.npy") 31 | assert_array Numo::UInt16[0...10], act 32 | end 33 | 34 | def test_uint32 35 | act = Npy.load("test/support/types/uint32.npy") 36 | assert_array Numo::UInt32[0...10], act 37 | end 38 | 39 | def test_uint64 40 | act = Npy.load("test/support/types/uint64.npy") 41 | assert_array Numo::UInt64[0...10], act 42 | end 43 | 44 | def test_float16 45 | error = assert_raises Npy::Error do 46 | Npy.load("test/support/types/float16.npy") 47 | end 48 | assert_includes error.message, "Type not supported" 49 | end 50 | 51 | def test_float32 52 | act = Npy.load("test/support/types/float32.npy") 53 | assert_array Numo::SFloat[0...10], act 54 | end 55 | 56 | def test_float64 57 | act = Npy.load("test/support/types/float64.npy") 58 | assert_array Numo::DFloat[0...10], act 59 | end 60 | 61 | def test_complex64 62 | act = Npy.load("test/support/types/complex64.npy") 63 | assert_array Numo::SComplex[0...10], act 64 | end 65 | 66 | def test_complex128 67 | act = Npy.load("test/support/types/complex128.npy") 68 | assert_array Numo::DComplex[0...10], act 69 | end 70 | 71 | def test_bool 72 | act = Npy.load("test/support/types/bool.npy") 73 | assert_array Numo::UInt8.cast([0] + ([1] * 9)), act 74 | end 75 | end 76 | --------------------------------------------------------------------------------