singlestoredb 0.8.8__cp36-abi3-win32.whl → 0.9.0__cp36-abi3-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of singlestoredb might be problematic. Click here for more details.

Files changed (41) hide show
  1. _singlestoredb_accel.pyd +0 -0
  2. singlestoredb/__init__.py +1 -1
  3. singlestoredb/config.py +6 -0
  4. singlestoredb/exceptions.py +24 -0
  5. singlestoredb/functions/__init__.py +1 -0
  6. singlestoredb/functions/decorator.py +165 -0
  7. singlestoredb/functions/dtypes.py +1396 -0
  8. singlestoredb/functions/ext/__init__.py +2 -0
  9. singlestoredb/functions/ext/asgi.py +357 -0
  10. singlestoredb/functions/ext/json.py +49 -0
  11. singlestoredb/functions/ext/rowdat_1.py +111 -0
  12. singlestoredb/functions/signature.py +607 -0
  13. singlestoredb/management/billing_usage.py +148 -0
  14. singlestoredb/management/manager.py +42 -1
  15. singlestoredb/management/organization.py +85 -0
  16. singlestoredb/management/utils.py +118 -1
  17. singlestoredb/management/workspace.py +881 -5
  18. singlestoredb/mysql/__init__.py +12 -10
  19. singlestoredb/mysql/_auth.py +3 -1
  20. singlestoredb/mysql/charset.py +12 -11
  21. singlestoredb/mysql/connection.py +4 -3
  22. singlestoredb/mysql/constants/CLIENT.py +0 -1
  23. singlestoredb/mysql/constants/COMMAND.py +0 -1
  24. singlestoredb/mysql/constants/CR.py +0 -2
  25. singlestoredb/mysql/constants/ER.py +0 -1
  26. singlestoredb/mysql/constants/FIELD_TYPE.py +0 -1
  27. singlestoredb/mysql/constants/FLAG.py +0 -1
  28. singlestoredb/mysql/constants/SERVER_STATUS.py +0 -1
  29. singlestoredb/mysql/converters.py +49 -28
  30. singlestoredb/mysql/err.py +3 -3
  31. singlestoredb/mysql/optionfile.py +4 -4
  32. singlestoredb/mysql/protocol.py +2 -1
  33. singlestoredb/mysql/times.py +3 -4
  34. singlestoredb/tests/test2.sql +1 -0
  35. singlestoredb/tests/test_management.py +393 -3
  36. singlestoredb/tests/test_udf.py +698 -0
  37. {singlestoredb-0.8.8.dist-info → singlestoredb-0.9.0.dist-info}/METADATA +1 -1
  38. {singlestoredb-0.8.8.dist-info → singlestoredb-0.9.0.dist-info}/RECORD +41 -29
  39. {singlestoredb-0.8.8.dist-info → singlestoredb-0.9.0.dist-info}/LICENSE +0 -0
  40. {singlestoredb-0.8.8.dist-info → singlestoredb-0.9.0.dist-info}/WHEEL +0 -0
  41. {singlestoredb-0.8.8.dist-info → singlestoredb-0.9.0.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,7 @@
2
2
  # type: ignore
3
3
  """SingleStoreDB HTTP connection testing."""
4
4
  import os
5
+ import pathlib
5
6
  import random
6
7
  import re
7
8
  import secrets
@@ -12,6 +13,9 @@ import pytest
12
13
  import singlestoredb as s2
13
14
 
14
15
 
16
+ TEST_DIR = pathlib.Path(os.path.dirname(__file__))
17
+
18
+
15
19
  def clean_name(s):
16
20
  """Change all non-word characters to -."""
17
21
  return re.sub(r'[^\w]', r'-', s).replace('_', '-').lower()
@@ -299,6 +303,392 @@ class TestWorkspace(unittest.TestCase):
299
303
  assert 'endpoint' in cm.exception.msg, cm.exception.msg
300
304
 
301
305
 
302
- if __name__ == '__main__':
303
- import nose2
304
- nose2.main()
306
+ @pytest.mark.management
307
+ class TestStages(unittest.TestCase):
308
+
309
+ manager = None
310
+ wg = None
311
+ password = None
312
+
313
+ @classmethod
314
+ def setUpClass(cls):
315
+ cls.manager = s2.manage_workspaces()
316
+
317
+ us_regions = [x for x in cls.manager.regions if 'US' in x.name]
318
+ cls.password = secrets.token_urlsafe(20)
319
+
320
+ name = clean_name(secrets.token_urlsafe(20)[:20])
321
+
322
+ cls.wg = cls.manager.create_workspace_group(
323
+ f'wg-test-{name}',
324
+ region=random.choice(us_regions).id,
325
+ admin_password=cls.password,
326
+ firewall_ranges=['0.0.0.0/0'],
327
+ )
328
+
329
+ @classmethod
330
+ def tearDownClass(cls):
331
+ if cls.wg is not None:
332
+ cls.wg.terminate(force=True)
333
+ cls.wg = None
334
+ cls.manager = None
335
+ cls.password = None
336
+
337
+ def test_upload_file(self):
338
+ st = self.wg.stages
339
+
340
+ root = st.info('')
341
+ assert str(root.path) == '.'
342
+ assert root.type == 'directory'
343
+
344
+ # Upload file
345
+ f = st.upload_file(TEST_DIR / 'test.sql', 'upload_test.sql')
346
+ assert str(f.path) == 'upload_test.sql'
347
+ assert f.type == 'file'
348
+
349
+ # Download and compare to original
350
+ txt = f.download(encoding='utf-8')
351
+ assert txt == open(TEST_DIR / 'test.sql').read()
352
+
353
+ # Make sure we can't overwrite
354
+ with self.assertRaises(OSError):
355
+ st.upload_file(TEST_DIR / 'test.sql', 'upload_test.sql')
356
+
357
+ # Force overwrite with new content
358
+ f = st.upload_file(TEST_DIR / 'test2.sql', 'upload_test.sql', overwrite=True)
359
+ assert str(f.path) == 'upload_test.sql'
360
+ assert f.type == 'file'
361
+
362
+ # Verify new content
363
+ txt = f.download(encoding='utf-8')
364
+ assert txt == open(TEST_DIR / 'test2.sql').read()
365
+
366
+ # Try to upload folder
367
+ with self.assertRaises(IsADirectoryError):
368
+ st.upload_file(TEST_DIR, 'test3.sql')
369
+
370
+ lib = st.mkdir('/lib')
371
+ assert str(lib.path) == 'lib'
372
+ assert lib.type == 'directory'
373
+
374
+ # Try to overwrite stage folder with file
375
+ with self.assertRaises(IsADirectoryError):
376
+ st.upload_file(TEST_DIR / 'test2.sql', lib.path, overwrite=True)
377
+
378
+ # Write file into folder
379
+ f = st.upload_file(TEST_DIR / 'test2.sql', lib.path / 'upload_test2.sql')
380
+ assert str(f.path) == 'lib/upload_test2.sql'
381
+ assert f.type == 'file'
382
+
383
+ def test_open(self):
384
+ st = self.wg.stages
385
+
386
+ # See if error is raised for non-existent file
387
+ with self.assertRaises(s2.ManagementError):
388
+ st.open('open_test.sql', 'r')
389
+
390
+ # Load test file
391
+ st.upload_file(TEST_DIR / 'test.sql', 'open_test.sql')
392
+
393
+ # Read file using `open`
394
+ with st.open('open_test.sql', 'r') as rfile:
395
+ assert rfile.read() == open(TEST_DIR / 'test.sql').read()
396
+
397
+ # Read file using `open` with 'rt' mode
398
+ with st.open('open_test.sql', 'rt') as rfile:
399
+ assert rfile.read() == open(TEST_DIR / 'test.sql').read()
400
+
401
+ # Read file using `open` with 'rb' mode
402
+ with st.open('open_test.sql', 'rb') as rfile:
403
+ assert rfile.read() == open(TEST_DIR / 'test.sql', 'rb').read()
404
+
405
+ # Read file using `open` with 'rb' mode
406
+ with self.assertRaises(ValueError):
407
+ with st.open('open_test.sql', 'b') as rfile:
408
+ pass
409
+
410
+ # Attempt overwrite file using `open` with mode 'x'
411
+ with self.assertRaises(OSError):
412
+ with st.open('open_test.sql', 'x') as wfile:
413
+ pass
414
+
415
+ # Attempt overwrite file using `open` with mode 'w'
416
+ with st.open('open_test.sql', 'w') as wfile:
417
+ wfile.write(open(TEST_DIR / 'test2.sql').read())
418
+
419
+ txt = st.download('open_test.sql', encoding='utf-8')
420
+
421
+ assert txt == open(TEST_DIR / 'test2.sql').read()
422
+
423
+ # Test writer without context manager
424
+ wfile = st.open('open_raw_test.sql', 'w')
425
+ for line in open(TEST_DIR / 'test.sql'):
426
+ wfile.write(line)
427
+ wfile.close()
428
+
429
+ txt = st.download('open_raw_test.sql', encoding='utf-8')
430
+
431
+ assert txt == open(TEST_DIR / 'test.sql').read()
432
+
433
+ # Test reader without context manager
434
+ rfile = st.open('open_raw_test.sql', 'r')
435
+ txt = ''
436
+ for line in rfile:
437
+ txt += line
438
+ rfile.close()
439
+
440
+ assert txt == open(TEST_DIR / 'test.sql').read()
441
+
442
+ def test_os_directories(self):
443
+ st = self.wg.stages
444
+
445
+ # mkdir
446
+ st.mkdir('mkdir_test_1')
447
+ st.mkdir('mkdir_test_2')
448
+ st.mkdir('mkdir_test_2/nest_1/nest_2')
449
+ st.mkdir('mkdir_test_3')
450
+
451
+ assert st.exists('mkdir_test_1')
452
+ assert st.exists('mkdir_test_2')
453
+ assert st.exists('mkdir_test_2/nest_1')
454
+ assert st.exists('mkdir_test_2/nest_1/nest_2')
455
+ assert not st.exists('foo')
456
+ assert not st.exists('foo/bar')
457
+
458
+ assert st.is_dir('mkdir_test_1')
459
+ assert st.is_dir('mkdir_test_2')
460
+ assert st.is_dir('mkdir_test_2/nest_1')
461
+ assert st.is_dir('mkdir_test_2/nest_1/nest_2')
462
+
463
+ assert not st.is_file('mkdir_test_1')
464
+ assert not st.is_file('mkdir_test_2')
465
+ assert not st.is_file('mkdir_test_2/nest_1')
466
+ assert not st.is_file('mkdir_test_2/nest_1/nest_2')
467
+
468
+ out = st.listdir('/')
469
+ assert 'mkdir_test_1' in out
470
+ assert 'mkdir_test_2' in out
471
+ assert 'mkdir_test_2/nest_1/nest_2' not in out
472
+
473
+ out = st.listdir('/', recursive=True)
474
+ assert 'mkdir_test_1' in out
475
+ assert 'mkdir_test_2' in out
476
+ assert 'mkdir_test_2/nest_1/nest_2' in out
477
+
478
+ out = st.listdir('mkdir_test_2')
479
+ assert 'mkdir_test_1' not in out
480
+ assert 'nest_1' in out
481
+ assert 'nest_2' not in out
482
+ assert 'nest_1/nest_2' not in out
483
+
484
+ out = st.listdir('mkdir_test_2', recursive=True)
485
+ assert 'mkdir_test_1' not in out
486
+ assert 'nest_1' in out
487
+ assert 'nest_2' not in out
488
+ assert 'nest_1/nest_2' in out
489
+
490
+ # rmdir
491
+ before = st.listdir('/', recursive=True)
492
+ st.rmdir('mkdir_test_1')
493
+ after = st.listdir('/', recursive=True)
494
+ assert 'mkdir_test_1' in before
495
+ assert 'mkdir_test_1' not in after
496
+ assert list(sorted(before)) == list(sorted(after + ['mkdir_test_1']))
497
+
498
+ with self.assertRaises(OSError):
499
+ st.rmdir('mkdir_test_2')
500
+
501
+ st.upload_file(TEST_DIR / 'test.sql', 'mkdir_test.sql')
502
+
503
+ with self.assertRaises(NotADirectoryError):
504
+ st.rmdir('mkdir_test.sql')
505
+
506
+ # removedirs
507
+ before = st.listdir('/')
508
+ st.removedirs('mkdir_test_2')
509
+ after = st.listdir('/')
510
+ assert 'mkdir_test_2' in before
511
+ assert 'mkdir_test_2' not in after
512
+ assert list(sorted(before)) == list(sorted(after + ['mkdir_test_2']))
513
+
514
+ with self.assertRaises(NotADirectoryError):
515
+ st.removedirs('mkdir_test.sql')
516
+
517
+ def test_os_files(self):
518
+ st = self.wg.stages
519
+
520
+ st.upload_file(TEST_DIR / 'test.sql', 'files_test.sql')
521
+ st.upload_file(TEST_DIR / 'test.sql', 'files_test_1/nest_1/nested_files_test.sql')
522
+ st.upload_file(
523
+ TEST_DIR / 'test.sql',
524
+ 'files_test_1/nest_1/nested_files_test_2.sql',
525
+ )
526
+
527
+ # remove
528
+ with self.assertRaises(IsADirectoryError):
529
+ st.remove('files_test_1')
530
+
531
+ before = st.listdir('/')
532
+ st.remove('files_test.sql')
533
+ after = st.listdir('/')
534
+ assert 'files_test.sql' in before
535
+ assert 'files_test.sql' not in after
536
+ assert list(sorted(before)) == list(sorted(after + ['files_test.sql']))
537
+
538
+ before = st.listdir('files_test_1/nest_1')
539
+ st.remove('files_test_1/nest_1/nested_files_test.sql')
540
+ after = st.listdir('files_test_1/nest_1')
541
+ assert 'nested_files_test.sql' in before
542
+ assert 'nested_files_test.sql' not in after
543
+ assert st.is_dir('files_test_1/nest_1')
544
+
545
+ # Removing the last file also removes empty directories
546
+ st.remove('files_test_1/nest_1/nested_files_test_2.sql')
547
+ assert not st.is_file('files_test_1/nest_1/nested_files_test_2.sql')
548
+ assert not st.is_dir('files_test_1/nest_1')
549
+ assert not st.is_dir('files_test_1')
550
+
551
+ def test_os_rename(self):
552
+ st = self.wg.stages
553
+
554
+ st.upload_file(TEST_DIR / 'test.sql', 'rename_test.sql')
555
+ st.upload_file(
556
+ TEST_DIR / 'test.sql',
557
+ 'rename_test_1/nest_1/nested_rename_test.sql',
558
+ )
559
+ st.upload_file(
560
+ TEST_DIR / 'test.sql',
561
+ 'rename_test_1/nest_1/nested_rename_test_2.sql',
562
+ )
563
+
564
+ # rename file
565
+ assert 'rename_test.sql' in st.listdir('/')
566
+ assert 'rename_test_2.sql' not in st.listdir('/')
567
+ st.rename('rename_test.sql', 'rename_test_2.sql')
568
+ assert 'rename_test.sql' not in st.listdir('/')
569
+ assert 'rename_test_2.sql' in st.listdir('/')
570
+
571
+ # rename directory
572
+ assert 'rename_test_1' in st.listdir('/')
573
+ assert 'rename_test_2' not in st.listdir('/')
574
+ st.rename('rename_test_1', 'rename_test_2')
575
+ assert 'rename_test_1' not in st.listdir('/')
576
+ assert 'rename_test_2' in st.listdir('/')
577
+ assert st.is_file('rename_test_2/nest_1/nested_rename_test.sql')
578
+ assert st.is_file('rename_test_2/nest_1/nested_rename_test_2.sql')
579
+
580
+ # rename nested
581
+ assert 'rename_test_2/nest_1/nested_rename_test.sql' in st.listdir(
582
+ '/', recursive=True,
583
+ )
584
+ assert 'rename_test_2/nest_1/nested_rename_test_3.sql' not in st.listdir(
585
+ '/', recursive=True,
586
+ )
587
+ st.rename(
588
+ 'rename_test_2/nest_1/nested_rename_test.sql',
589
+ 'rename_test_2/nest_1/nested_rename_test_3.sql',
590
+ )
591
+ assert 'rename_test_2/nest_1/nested_rename_test.sql' not in st.listdir(
592
+ '/', recursive=True,
593
+ )
594
+ assert 'rename_test_2/nest_1/nested_rename_test_3.sql' in st.listdir(
595
+ '/', recursive=True,
596
+ )
597
+ assert not st.is_file('rename_test_2/nest_1/nested_rename_test.sql')
598
+ assert st.is_file('rename_test_2/nest_1/nested_rename_test_2.sql')
599
+ assert st.is_file('rename_test_2/nest_1/nested_rename_test_3.sql')
600
+
601
+ # non-existent file
602
+ with self.assertRaises(OSError):
603
+ st.rename('rename_foo.sql', 'rename_foo_2.sql')
604
+
605
+ # overwrite
606
+ with self.assertRaises(OSError):
607
+ st.rename(
608
+ 'rename_test_2.sql',
609
+ 'rename_test_2/nest_1/nested_rename_test_3.sql',
610
+ )
611
+
612
+ st.rename(
613
+ 'rename_test_2.sql',
614
+ 'rename_test_2/nest_1/nested_rename_test_3.sql', overwrite=True,
615
+ )
616
+
617
+ def test_stages_object(self):
618
+ st = self.wg.stages
619
+
620
+ f1 = st.upload_file(TEST_DIR / 'test.sql', 'obj_test.sql')
621
+ f2 = st.upload_file(TEST_DIR / 'test.sql', 'obj_test/nest_1/obj_test.sql')
622
+ d2 = st.info('obj_test/nest_1')
623
+
624
+ # is_file / is_dir
625
+ assert not f1.is_dir()
626
+ assert f1.is_file()
627
+ assert not f2.is_dir()
628
+ assert f2.is_file()
629
+ assert d2.is_dir()
630
+ assert not d2.is_file()
631
+
632
+ # abspath / basename / dirname / exists
633
+ assert f1.abspath() == 'obj_test.sql'
634
+ assert f1.basename() == 'obj_test.sql'
635
+ assert f1.dirname() == ''
636
+ assert f1.exists()
637
+ assert f2.abspath() == 'obj_test/nest_1/obj_test.sql'
638
+ assert f2.basename() == 'obj_test.sql'
639
+ assert f2.dirname() == 'obj_test/nest_1'
640
+ assert f2.exists()
641
+ assert d2.abspath() == 'obj_test/nest_1'
642
+ assert d2.basename() == 'nest_1'
643
+ assert d2.dirname() == 'obj_test'
644
+ assert d2.exists()
645
+
646
+ # download
647
+ assert f1.download(encoding='utf-8') == open(TEST_DIR / 'test.sql', 'r').read()
648
+ assert f1.download() == open(TEST_DIR / 'test.sql', 'rb').read()
649
+
650
+ # remove
651
+ with self.assertRaises(IsADirectoryError):
652
+ d2.remove()
653
+
654
+ assert st.is_file('obj_test.sql')
655
+ f1.remove()
656
+ assert not st.is_file('obj_test.sql')
657
+
658
+ # removedirs
659
+ with self.assertRaises(NotADirectoryError):
660
+ f2.removedirs()
661
+
662
+ assert st.exists(d2.path)
663
+ d2.removedirs()
664
+ assert not st.exists(d2.path)
665
+
666
+ # rmdir
667
+ f1 = st.upload_file(TEST_DIR / 'test.sql', 'obj_test.sql')
668
+ d2 = st.mkdir('obj_test/nest_1')
669
+
670
+ assert st.exists(f1.path)
671
+ assert st.exists(d2.path)
672
+
673
+ with self.assertRaises(NotADirectoryError):
674
+ f1.rmdir()
675
+
676
+ assert st.exists(f1.path)
677
+ assert st.exists(d2.path)
678
+
679
+ d2.rmdir()
680
+
681
+ assert not st.exists('obj_test/nest_1')
682
+ assert not st.exists('obj_test')
683
+
684
+ # mtime / ctime
685
+ assert f1.getmtime() > 0
686
+ assert f1.getctime() > 0
687
+
688
+ # rename
689
+ assert st.exists('obj_test.sql')
690
+ assert not st.exists('obj_test_2.sql')
691
+ f1 = f1.rename('obj_test_2.sql')
692
+ assert not st.exists('obj_test.sql')
693
+ assert st.exists('obj_test_2.sql')
694
+ assert f1.abspath() == 'obj_test_2.sql'