-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdiary.html
8764 lines (7552 loc) · 467 KB
/
diary.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" href="style.css" type="text/css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<title>Thesis Repository</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light navbar-custom ">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="index.html">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="diary.html">Diary</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="phases.html" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Phases
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="phase1.html">Phase 1</a>
<a class="dropdown-item" href="phase2.html">Phase 2</a>
<a class="dropdown-item" href="phase3.html">Phase 3</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="meetings.html">Meetings</a>
</li>
</ul>
</div>
</nav>
<h1>Diary</h1>
<div id="accordion">
<div class="card">
<div class="card-header" id="headingOne">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Week #1 (01-14-20)
</button>
</h5>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
<div class="card-body">
<h2>UnitTest Introduction</h2>
<p>UnitTest is a test runner built into a python library, containing both a testing framework and a test runner.</p>
<p><em>Requirements:</em></p>
<ul>
<li>tests must be included into <em>classes</em> as <em>methods</em> </li>
<li>instead of the built-in statement "assert", the <em>special assertion methods in unittest.TestCase class </em> must be used </li>
</ul>
<h2>Example 1</h2>
<p>file test_sum_2.py</p>
<div class="codebg">
<code>
<pre>
def test_sum():
assert sum([1, 2, 3]) == 6, "Should be 6"
def test_sum_tuple():
assert sum((1, 2, 2)) == 6, "Should be 6"
if __name__ == "__main__":
test_sum()
test_sum_tuple()
print("Everything passed")
</pre>
</code>
</div>
<p>Steps of the procedure to convert the aforementioned example into a unittest case:</p>
<ol>
<li> <em>import unittest</em> from the library</li>
<li>create a <em>TestSum class</em>, inherited from TestCase class</li>
<li>use <em>self</em> as first argument, so that functions are turned into methods</li>
<li>change assertions, so to use <em>self.assertEqual() method from the TestCase class</em></li>
<li>change the command-line entry point to call unittest.main()</li>
</ol>
<div class="container">
<img src="unittest1.png" alt="unittest1">
</div>
<div class="info"><p><span class="remind">assert</span><br>The assert keyword lets you test if a condition in your code returns True, if not, the program will raise an AssertionError.
You can write a message to be written if the code returns False</p>
<div class="codebg">
<code><pre>
x = "hello"
#if condition returns True, then nothing happens:
assert x == "hello"
#if condition returns False, AssertionError is raised:
assert x == "goodbye"
</pre></code></div>
<p>Source: <a href="https://www.w3schools.com/python/ref_keyword_assert.asp#:~:text=The%20assert%20keyword%20is%20used,False%2C%20check%20the%20example%20below.">w3school.com</a></p>
</div>
<p>Source:<a href="https://realpython.com/python-testing/">realpython.com</a></p>
<h2>Example 2</h2>
<div class="codebg">
<code>
<pre>
import unittest
def add_fish_to_aquarium(fish_list):
if len(fish_list) > 10:
raise ValueError("A maximum of 10 fish can be added to the aquarium")
return {"tank_a": fish_list}
class TestAddFishToAquarium(unittest.TestCase):
def test_add_fish_to_aquarium_success(self):
actual = add_fish_to_aquarium(fish_list=["shark", "tuna"])
expected = {"tank_a": ["shark", "tuna"]}
self.assertEqual(actual, expected)
</pre>
</code>
</div>
<p>Procedure:</p>
<ol>
<li>Import unittest</li>
<li>Define the function to test, defining also cases in which the function raises errors</li>
<li>Define a class as a subclass of unittest.TestCase</li>
<li>Define one or more methods of the defined class (with self argument). This test function calls the function to test with a specific input and verifies whether the actual returned value matches the expected one</li>
<li>Execute the test (from command line: python -m unittest test_add_fish_to_aquarium.py)</li>
</ol>
<p>Source <a href="https://www.digitalocean.com/community/tutorials/how-to-use-unittest-to-write-a-test-case-for-a-function-in-python">https://www.digitalocean.com/</a></p>
<h2>Example 3</h2>
<div class="codebg">
<code>
<pre>
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
</pre>
</code>
</div>
<p>Procedure:</p>
<ul>
<li>import unittest</li>
<li>a testcase is created by subclassing unittest.TestCase.</li>
<li>individual tests are defined with methods whose names start with the letters test, in order to inform the test runner about which methods represent tests.</li>
<li>each test is a call to assertEqual() to check for an expected result; assertTrue() or assertFalse() to verify a condition; or assertRaises() to verify that a specific exception gets raised. Differently from the simple assert statement, these methods allow the test runner to accumulate all test results and produce a report.</li>
<li>setUp() and tearDown() methods allow you to define instructions that will be executed before and after each test method.</li>
<li>unittest.main() is a simple way to run the tests. Provides a command-line interface to the test script. </li>
<li>Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, so that each test's outcome can be seen individually.</li>
<div class="container">
<img src="prompt.png" alt="promptscreenshot">
</div>
</ul>
<p>Source <a href="https://docs.python.org/3/library/unittest.html">unittest documentation</a></p>
<h2>Classes and functions</h2>
<div class="info"><span class="remind">tearDown()</span><br>
<p>Method called immediately after the test method has been called and the result recorded. This is called even if the test method raised an exception, so the implementation in subclasses may need to be particularly careful about checking internal state. This method will only be called if the setUp() succeeds, regardless of the outcome of the test method.</p>
</div>
<div class="info"><span class="remind">setUp()</span><br>
<p>Method called to prepare the test fixture. This is called immediately before calling the test method; other than AssertionError or SkipTest, any exception raised by this method will be considered an error rather than a test failure. </p>
</div>
<div class="info"><span class="remind">assertEqual(first, second, msg=None)</span><br>
<p>Test that first and second are not equal. If the values do compare equal, the test will fail. </p>
</div>
<div class="info"><span class="remind">assertNotEqual(first, second, msg=None)</span><br>
<p>Test that first and second are not equal. If the values do compare equal, the test will fail. </p>
</div>
<div class="info"><span class="remind">assertTrue(expr, second, msg=None) & assertFalse(expr, second, msg=None)</span><br>
<p>Test that expr is true (or false). </p>
</div>
<div class="info"><span class="remind">assertIs(first, second, msg=None) & assertIsNot(first, second, msg=None)</span><br>
<p>Test that first and second are (or are not) the same object. </p>
</div>
<div class="info"><span class="remind">assertIsNone(expr, msg=None) & assertIsNotNone(expr, msg=None)</span><br>
<p>Test that expr is (or is not) None </p>
</div>
<div class="info"><span class="remind">assertIn(member, container, msg=None) & assertNotIn(member, container, msg=None)</span><br>
<p>Test that member is (or is not) in container.</p>
</div>
<div class="info"><span class="remind">assertIsInstance(obj, cls, msg=None) & assertNotIsInstance(obj, cls, msg=None)</span><br>
<p>Test that obj is (or is not) an instance of cls (which can be a class or a tuple of classes, as supported by isinstance()). To check for the exact type, use assertIs(type(obj), cls). </p>
</div>
<div class="info"><span class="remind">assertCountEqual(first, second, msg=None)</span><br>
<p>Test that sequence first contains the same elements as second, regardless of their order. </p>
</div>
<div class="info"><span class="remind">assertMultiLineEqual(first, second, msg=None)</span><br>
<p>Test that the multiline string first is equal to the string second. </p>
</div>
<div class="info"><span class="remind">assertListEqual(first, second, msg=None) & assertTupleEqual(first, second, msg=None)</span><br>
<p>Tests that two lists or tuples are equal. If not, an error message is constructed that shows only the differences between the two.</p>
</div>
<div class="info"><span class="remind">assertSetEqual(first, second, msg=None)</span><br>
<p>Tests that two sets are equal. If not, an error message is constructed that lists the differences between the sets. This method is used by default when comparing sets or frozensets with assertEqual().</p>
</div>
<div class="info"><span class="remind">assertDictEqual(first, second, msg=None)</span><br>
<p>Test that two dictionaries are equal. If not, an error message is constructed that shows the differences in the dictionaries. This method will be used by default to compare dictionaries in calls to assertEqual().</p>
</div>
<div class="info"><span class="remind">assertListEqual(first, second, msg=None) & assertTupleEqual(first, second, msg=None)</span><br>
<p>Tests that two lists or tuples are equal. If not, an error message is constructed that shows only the differences between the two.</p>
</div>
<p>Source <a href="https://docs.python.org/3/library/unittest.html">unittest documentation</a></p>
<h2>Organizing test code</h2>
<ul>
<li>In unittest, test cases are unittest.TestCase instances.</li>
<li>The testing code of a TestCase instance should be entirely self contained, in order to be runnable either in isolation or in combination</li>
<li>In order to test, the assert*() methods provided by the TestCase base class are used. When the test fails, an exception is raised with an explanatory message, and unittest identifies the test case as a failure.</li>
<li>When many tests with repetitive set ups have to be executed, setUP() method can be automatically called for every test run. </li>
<li>tearDown() method, similarly, tidies up after the test method has been run</li>
<li>Such a working environment for the testing code is called a test fixture. A new TestCase instance is created as a unique test fixture used to execute each individual test method. Thus setUp(), tearDown(), and __init__() will be called once per test.</li>
<li>Test suite, represented by unittest’s TestSuite class, is a mechanism to group TestCase implementations according to the features they test.</li>
</ul>
<p>Source <a href="https://docs.python.org/3/library/unittest.html">unittest documentation</a></p>
<h2>Reusing old test code</h2>
<p>FunctionTestCase class: TestCase subclass to wrap an existing test function. </p>
<div class="codebg">
<code>
<pre>
testcase = unittest.FunctionTestCase(testSomething,
setUp=makeSomethingDB,
tearDown=deleteSomethingDB)
</pre>
</code>
</div>
<p>Source <a href="https://docs.python.org/3/library/unittest.html">unittest documentation</a></p>
<h2>index/test/09_croci.py/</h2>
<div class="codebg">
<code>
<pre>
import unittest
from index.coci.glob import process
from os import sep, makedirs
from os.path import exists
from shutil import rmtree
from index.storer.csvmanager import CSVManager
from index.croci.crowdsourcedcitationsource import CrowdsourcedCitationSource
from csv import DictReader
class CROCITest(unittest.TestCase):
def setUp(self):
self.input_file = "index%stest_data%scroci_dump%ssource.csv" % (sep, sep, sep)
self.citations = "index%stest_data%scroci_dump%scitations.csv" % (sep, sep, sep)
def test_citation_source(self):
ccs = CrowdsourcedCitationSource(self.input_file)
new = []
cit = ccs.get_next_citation_data()
while cit is not None:
citing, cited, creation, timespan, journal_sc, author_sc = cit
new.append({
"citing": citing,
"cited": cited,
"creation": "" if creation is None else creation,
"timespan": "" if timespan is None else timespan,
"journal_sc": "no" if journal_sc is None else journal_sc,
"author_sc": "no" if author_sc is None else author_sc
})
cit = ccs.get_next_citation_data()
with open(self.citations) as f:
old = list(DictReader(f))
self.assertEqual(new, old)
</pre>
</code>
</div>
<div class="info"><span class="remind">from index.coci.glob import process</span><br>
<div class="codebg">
<code>
<pre>
def process(input_dir, output_dir):
if not exists(output_dir):
makedirs(output_dir)
</pre>
</code>
</div>
</div>
<div class="info"><span class="remind">from os import sep, makedirs</span><br>
<ol>
<li> <b>os.sep</b>: The character used by the operating system to separate pathname components. This is '/' for POSIX and '\\' for Windows. Note that knowing this is not sufficient to be able to parse or concatenate pathnames — use os.path.split() and os.path.join() — but it is occasionally useful. Also available via os.path. </li>
<li> <b>os.makedirs</b>: os.makedirs(name, mode=0o777, exist_ok=False) is a recursive directory creation function. Like mkdir(), but makes all intermediate-level directories needed to contain the leaf directory. </li>
</ol>
</div>
<div class="info"><span class="remind">from os.path import exists</span><br>
<p> <b>os.path.exists</b>:os.path.exists(path)
return True if path refers to an existing path or an open file descriptor. Returns False for broken symbolic links. On some platforms, this function may return False if permission is not granted to execute os.stat() on the requested file, even if the path physically exists. In more recent versions (Python 3.3 and 3.6) path can be an integer (True is returned if it is an open file descriptor, False otherwise) and paths like objects are now accepted. </p>
</div>
<div class="info"><span class="remind">from shutil import rmtree</span><br>
<p> <b>shutil.rmtree</b>: shutil.rmtree(path, ignore_errors=False, onerror=None)
delete an entire directory tree; path must point to a directory (but not a symbolic link to a directory). If ignore_errors is true, errors resulting from failed removals will be ignored; if false or omitted, such errors are handled by calling a handler specified by onerror or, if that is omitted, they raise an exception. </p>
</div>
<div class="info"><span class="remind">from index.storer.csvmanager import CSVManager</span><br>
<div class="codebg">
<code>
<pre>
class CSVManager(object):
"""This class is able to load a simple CSV composed by two fields, 'id' and
'value', and then to index all its items in a structured form so as to be
easily queried. In addition, it allows one to store new information in the CSV,
if needed."""
def __init__(self, csv_path=None, line_threshold=10000, store_new=True):
self.csv_path = csv_path
self.data = {}
self.store_new = store_new
if csv_path is not None and exists(csv_path):
CSVManager.__load_all_csv_files([csv_path], self.__load_csv, line_threshold=line_threshold)
@staticmethod
def load_csv_column_as_set(file_or_dir_path, key, line_threshold=10000):
result = set()
if exists(file_or_dir_path):
file_to_process = []
if isdir(file_or_dir_path):
for cur_dir, cur_subdir, cur_files in walk(file_or_dir_path):
for cur_file in cur_files:
if cur_file.endswith(".csv"):
file_to_process.append(cur_dir + sep + cur_file)
else:
file_to_process.append(file_or_dir_path)
for item in CSVManager.__load_all_csv_files(file_to_process, CSVManager.__load_csv_by_key,
line_threshold=line_threshold, key=key):
result.update(item)
return result
@staticmethod
def __load_csv_by_key(csv_string, key):
result = set()
csv_metadata = DictReader(StringIO(csv_string), delimiter=',')
for row in csv_metadata:
result.add(row[key])
return result
@staticmethod
def __load_all_csv_files(list_of_csv_files, fun, line_threshold, **params):
result = []
header = None
for csv_path in list_of_csv_files:
with open(csv_path, encoding="utf-8") as f:
csv_content = ""
for idx, line in enumerate(f.readlines()):
if header is None:
header = line
csv_content = header
else:
if idx % line_threshold == 0:
result.append(fun(csv_content, **params))
csv_content = header
csv_content += line
result.append(fun(csv_content, **params))
return result
def get_value(self, id_string):
"""It returns the set of values associated to the input 'id_string',
or None if 'id_string' is not included in the CSV."""
if id_string in self.data:
return set(self.data[id_string])
def add_value(self, id_string, value):
"""It adds the value specified in the set of values associated to 'id_string'.
If the object was created with the option of storing also the data in a CSV
('store_new' = True, default behaviour), then it also add new data in the CSV."""
if id_string not in self.data:
self.data[id_string] = set()
if value not in self.data[id_string]:
self.data[id_string].add(value)
if self.csv_path is not None and self.store_new:
if not exists(self.csv_path):
with open(self.csv_path, "w") as f:
f.write('"id","value"\n')
with open(self.csv_path, "a") as f:
f.write('"%s","%s"\n' % (id_string.replace('"', '""'),
value.replace('"', '""')))
def __load_csv(self, csv_string):
csv_metadata = DictReader(StringIO(csv_string), delimiter=',')
for row in csv_metadata:
cur_id = row["id"]
if cur_id not in self.data:
self.data[cur_id] = set()
self.data[cur_id].add(row["value"])
</pre>
</code>
</div>
</div>
<div class="info"><span class="remind">from index.croci.crowdsourcedcitationsource import CrowdsourcedCitationSource</span><br>
<div class="codebg">
<code>
<pre>
class CrowdsourcedCitationSource(CSVFileCitationSource):
def __init__(self, src, local_name=""):
self.doi = DOIManager()
super(CrowdsourcedCitationSource, self).__init__(src, local_name)
def get_next_citation_data(self):
row = self._get_next_in_file()
while row is not None:
citing = self.doi.normalise(row.get("citing_id"))
cited = self.doi.normalise(row.get("cited_id"))
if citing is not None and cited is not None:
created = row.get("citing_publication_date")
if not created:
created = None
cited_pub_date = row.get("cited_publication_date")
if not cited_pub_date:
timespan = None
else:
c = Citation(None, None, created, None, cited_pub_date, None, None, None, None, "", None, None, None, None, None)
timespan = c.duration
self.update_status_file()
return citing, cited, created, timespan, None, None
self.update_status_file()
row = self._get_next_in_file()
remove(self.status_file)
</pre>
</code>
</div>
</div>
<div class="info"><span class="remind">from csv import DictReader</span><br>
<p> <b>class csv.DictReader</b>(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)
create an object that operates like a regular reader but maps the information in each row to a dict whose keys are given by the optional fieldnames parameter.
The fieldnames parameter is a sequence. If fieldnames is omitted, the values in the first row of file f will be used as the fieldnames. Regardless of how the fieldnames are determined, the dictionary preserves their original ordering.
If a row has more fields than fieldnames, the remaining data is put in a list and stored with the fieldname specified by restkey (which defaults to None). If a non-blank row has fewer fields than fieldnames, the missing values are filled-in with the value of restval (which defaults to None). </p>
<p>Example:</p>
<div class="codebg">
<code>
<pre>
>>> import csv
>>> with open('names.csv', newline='') as csvfile:
... reader = csv.DictReader(csvfile)
... for row in reader:
... print(row['first_name'], row['last_name'])
...
Eric Idle
John Cleese
>>> print(row)
{'first_name': 'John', 'last_name': 'Cleese'}
</pre>
</code>
</div>
</div>
<p>Sources:<a href="https://docs.python.org/3/library/">The Python Standard Library</a> and <a href="https://github.com/opencitations/index">OpenCitations Index</a> </p>
<h2>Exercises</h2>
<h3>Beginners 1</h3>
<div class="codebg">
<pre>
<code>
import unittest
def t(x, y):
return x + y - 2
class TestT(unittest.TestCase):
def test_t(self):
actual = t(x=5, y=6)
expected = 5+6-2
self.assertEqual(actual, expected)
</code>
</pre>
</div>
<p>In this way it works</p>
<div class="codebg">
<pre>
<code>
import unittest
class TestT(unittest.TestCase):
def test_t(self):
result = t(x, y)
expected = x + y -2
self.assertEqual(result, expected)
def t(x, y):
return x + y - 2
</code>
</pre>
</div>
<p>((In this way it doesn't. I think I know why but I'd like to clarify this point)) </p>
<div class="codebg">
<code>
<pre>
def t(x, y):
return x + y - 2
import unittest
class TestT(unittest.TestCase):
def test_t(self):
self.assertEqual(t(5,9), 12)
if __name__ == "__main__":
unittest.main()
</pre>
</code>
</div>
<p>In this way it works and I also have the result displayed in Pycharm console</p>
<h3>Beginners 2</h3>
<div class="codebg">
<code>
<pre>
def f(s1, s2):
if len(s1) > len(s2):
return -1
elif len(s1) < len(s2):
return 1
else:
return 0
import unittest
class TestF(unittest.TestCase):
def test_f(self):
self.assertEqual(f("dog","cat"), 0)
self.assertEqual(f("dog","monkey"), 1)
self.assertEqual(f("dog", "my"), -1)
if __name__ == "__main__":
unittest.main()
</pre>
</code>
</div>
<h3>Beginners 3</h3>
<div class="codebg">
<code>
<pre>
def f(s1, s2):
result = set()
for c in s1:
if c in s2:
result.add(c)
return result
import unittest
class TestF(unittest.TestCase):
def test_f(self):
self.assertEqual(f("123","435"), {"3"})
self.assertEqual(f("126","435"), set()) #if I use {} it doesn't work
self.assertEqual(f("brother","sister"), {"r","t","e"})
self.assertEqual(f("cat","catsitter"), {"c","a","t"})
if __name__ == "__main__":
unittest.main()
</pre>
</code>
</div>
<p>Original codes source: <a href="https://comp-think.github.io/">The CTP Book</a> </p>
<h2>Issues</h2>
<ol>
<li># check that s.split fails when the separator is not a string \\
with self.assertRaises(TypeError):\\
s.split(2)\\?</li>
<li>Why is unittest more efficient then other testing approaches?</li>
<li>In practice, when and how do we use assertRaises(TypeError)? </li>
<li>if __name__ == '__main__':\\
unittest.main()</li>
<li>In many of the tutorials I followed the code is launched through the command prompt. Is it necessary or suggested? Can I work with Pycharm only?</li>
<li>Is TestSuit necessary in our case? "In most cases, calling unittest.main() will do the right thing and collect all the module’s test cases for you and execute them."</li>
<li>Does the assertEqual have more or less the same function of the print part of the test case that we used in CTP course? (since -in order to make the test work- some values have to be assigned to the arguments of the tested function) </li>
<li>For now I'm only using assertEqual() since I have some troubles in understanding how all the other methods could be applied in tests (how can I do something more than testing if the result of the function matches the expected one? In OpenCitation which other ones are mainly used?).</li>
<li>SetUp(): real contexts of use (examples)? In particular setUp in CrociTest <br> self.input_file = "index%stest_data%scroci_dump%ssource.csv" % (sep, sep, sep) <br>
self.citations = "index%stest_data%scroci_dump%scitations.csv" % (sep, sep, sep)</li>
</ol>
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="headingTwo">
<h5 class="mb-0">
<button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
Week #2 (01-21-21)
</button>
</h5>
</div>
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordion">
<div class="card-body">
<h2>NIH library data</h2>
<h3>Ten examples</h3>
<p>I randomly extracted ten samples from the open_citation_collection.csv and I stored the data in a new csv file (open_citation_collection_sample.csv, then renamed source.csv).</p>
<div class="codebg"><code><pre>C:\Users\arimoretti\Desktop\TESI\icite>pip install subsample
Collecting subsample
Downloading https://files.pythonhosted.org/packages/21/86/ff247222b81baa8b47a9970c76e6f930662d7b9336e669f7e4b39857e674/subsample-0.0.6.tar.gz
Installing collected packages: subsample
Running setup.py install for subsample ... done
Successfully installed subsample-0.0.6
WARNING: You are using pip version 19.2.3, however version 21.0.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.
C:\Users\arimoretti\Desktop\TESI\icite>subsample -n 10 open_citation_collection.csv > open_citation_collection_sample.csv
LOG 03:21 > Data begins at 0
C:\Users\arimoretti\Desktop\TESI\icite></pre></code></div>
<ol>
<li>2140506,2942070</li>
<li>1523579,7097569</li>
<li>1509982,6501574</li>
<li>1968312,13673087</li>
<li>2330868,3958380</li>
<li>1854174,3037997</li>
<li>2038824,2494239</li>
<li>2373284,7189714</li>
<li>3591292,4092853</li>
<li>2368927,355650</li>
</ol>
<h3>Notes on format</h3>
<p>Before extracting data, we expected these to be either PMCID or PMID. The pure numeric format denotes that we are handling PMIDs.</p>
<p>OC process is based on the use of a <strong>tuple of six values</strong> derived from the citation source(citing, cited, created, timespan, journal_sc, author_sc). However, here we just have two of these values, which are also the only indispensable ones (i.e. citing + referenced/cited).</p>
<h2>Data mapping</h2>
<p>The 2 primary identifiers are not DOIs, but PubMedID. Since until now only DOIs have been managed by our process, some of these citations may already be present in Open Citations (COCI: doi to doi only). </p>
<p>In NIH dataset some articles probably have a doi, but exposed differently. So our options for the mapping are: </p>
<ol>
<li>use article additional data provided by icite</li>
<li>use external mapping datasets</li>
</ol>
<h3>External mapping tools</h3>
<h4>Results obtained with <a href="https://www.pmid2cite.com/pmid-to-doi-converter">www.pmid2cite.com</a></h4>
<table style="width: 117px;">
<tbody>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;"> </td>
<td style="height: 22px; width: 64.8px;">PMID citing</td>
<td style="height: 22px; width: 36px;"> DOI citing</td>
<td style="height: 22px; width: 36px;">PMID referenced</td>
<td style="height: 22px; width: 36px;">DOI referenced</td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">1</td>
<td style="height: 22px; width: 64.8px;"> 2140506</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1111/j.1445-5994.1990.tb01289.x" target="_blank">10.1111/j.1445-5994.1990.tb01289.x</a></td>
<td style="height: 22px; width: 36px;">2942070</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.7326/0003-4819-105-2-173" target="_blank">10.7326/0003-4819-105-2-173</a></td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">2</td>
<td style="height: 22px; width: 64.8px;"> 1523579</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1002/tera.1420460305" target="_blank">10.1002/tera.1420460305</a></td>
<td style="height: 22px; width: 36px;">7097569</td>
<td style="height: 22px; width: 36px;">Unable to resolve the DOI </td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">3</td>
<td style="height: 22px; width: 64.8px;"> 1509982</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1007/BF01990957" target="_blank">10.1007/BF01990957</a></td>
<td style="height: 22px; width: 36px;">6501574</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1172/JCI111604" target="_blank">10.1172/JCI111604</a></td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">4</td>
<td style="height: 22px; width: 64.8px;"> 1968312</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1016/0002-9149(90)90817-k" target="_blank">10.1016/0002-9149(90)90817-k</a></td>
<td style="height: 22px; width: 36px;">13673087</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1172/JCI103906" target="_blank">10.1172/JCI103906</a></td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">5</td>
<td style="height: 22px; width: 64.8px;"> 2330868</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1016/s0002-8703(05)80240-6" target="_blank">10.1016/s0002-8703(05)80240-6</a></td>
<td style="height: 22px; width: 36px;">3958380</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1016/s0735-1097(86)80214-5" target="_blank">10.1016/s0735-1097(86)80214-5</a></td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">6</td>
<td style="height: 22px; width: 64.8px;"> 1854174</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1128/aac.35.5.929" target="_blank">10.1128/aac.35.5.929</a></td>
<td style="height: 22px; width: 36px;">3037997</td>
<td style="height: 22px; width: 36px;">
<div id="buttonHide" class="out">
<p class="output"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1128/aac.31.4.497" target="_blank">10.1128/aac.31.4.497</a></p>
</div>
</td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">7</td>
<td style="height: 22px; width: 64.8px;"> 2038824</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1016/0165-2427(91)90031-7" target="_blank">10.1016/0165-2427(91)90031-7</a></td>
<td style="height: 22px; width: 36px;">2494239</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.3168/jds.S0022-0302(89)79089-5" target="_blank">10.3168/jds.S0022-0302(89)79089-5</a></td>
</tr>
<tr style="height: 22.6px;">
<td style="height: 22.6px; width: 15.2px;">8</td>
<td style="height: 22.6px; width: 64.8px;"> 2373284</td>
<td style="height: 22.6px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1111/j.1432-0436.1990.tb00437.x" target="_blank">10.1111/j.1432-0436.1990.tb00437.x</a></td>
<td style="height: 22.6px; width: 36px;">7189714</td>
<td style="height: 22.6px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1016/0014-4827(80)90437-1" target="_blank">10.1016/0014-4827(80)90437-1</a></td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">9</td>
<td style="height: 22px; width: 64.8px;"> 3591292</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1111/j.1651-2227.1987.tb10456.x" target="_blank">10.1111/j.1651-2227.1987.tb10456.x</a></td>
<td style="height: 22px; width: 36px;">4092853</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1111/j.1469-8749.1985.tb03805.x" target="_blank">10.1111/j.1469-8749.1985.tb03805.x</a></td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">10</td>
<td style="height: 22px; width: 64.8px;">2368927</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1002/ar.1092270109" target="_blank">10.1002/ar.1092270109</a></td>
<td style="height: 22px; width: 36px;">355650</td>
<td style="height: 22px; width: 36px;">Unable to resolve the DOI </td>
</tr>
</tbody>
</table>
<h4>Results obtained with <a href="https://www.ncbi.nlm.nih.gov/pmc/pmctopmid/#api">/www.ncbi.nlm.nih.gov</a></h4>
<table style="width: 117px;">
<tbody>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;"> </td>
<td style="height: 22px; width: 64.8px;">PMID citing</td>
<td style="height: 22px; width: 36px;"> DOI citing</td>
<td style="height: 22px; width: 36px;">PMID referenced</td>
<td style="height: 22px; width: 36px;">DOI referenced</td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">1</td>
<td style="height: 22px; width: 64.8px;"> 2140506</td>
<td style="height: 22px; width: 36px;">""</td>
<td style="height: 22px; width: 36px;">2942070</td>
<td style="height: 22px; width: 36px;">""</td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">2</td>
<td style="height: 22px; width: 64.8px;"> 1523579</td>
<td style="height: 22px; width: 36px;">""</td>
<td style="height: 22px; width: 36px;">7097569</td>
<td style="height: 22px; width: 36px;">""</td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">3</td>
<td style="height: 22px; width: 64.8px;"> 1509982</td>
<td style="height: 22px; width: 36px;">""</td>
<td style="height: 22px; width: 36px;">6501574</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1172/JCI111604" target="_blank">10.1172/JCI111604</a></td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">4</td>
<td style="height: 22px; width: 64.8px;"> 1968312</td>
<td style="height: 22px; width: 36px;">""</td>
<td style="height: 22px; width: 36px;">13673087</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1172/JCI103906" target="_blank">10.1172/JCI103906</a></td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">5</td>
<td style="height: 22px; width: 64.8px;"> 2330868</td>
<td style="height: 22px; width: 36px;">""</td>
<td style="height: 22px; width: 36px;">3958380</td>
<td style="height: 22px; width: 36px;">""</td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">6</td>
<td style="height: 22px; width: 64.8px;"> 1854174</td>
<td style="height: 22px; width: 36px;"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1128/aac.35.5.929" target="_blank">10.1128/aac.35.5.929</a></td>
<td style="height: 22px; width: 36px;">3037997</td>
<td style="height: 22px; width: 36px;">
<div id="buttonHide" class="out">
<p class="output"><a title="Link by DOI for the given PMID" href="https://doi.org/10.1128/aac.31.4.497" target="_blank">10.1128/aac.31.4.497</a></p>
</div>
</td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">7</td>
<td style="height: 22px; width: 64.8px;"> 2038824</td>
<td style="height: 22px; width: 36px;">""</td>
<td style="height: 22px; width: 36px;">2494239</td>
<td style="height: 22px; width: 36px;">""</td>
</tr>
<tr style="height: 22.6px;">
<td style="height: 22.6px; width: 15.2px;">8</td>
<td style="height: 22.6px; width: 64.8px;"> 2373284</td>
<td style="height: 22.6px; width: 36px;">""</td>
<td style="height: 22.6px; width: 36px;">7189714</td>
<td style="height: 22.6px; width: 36px;">""</td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">9</td>
<td style="height: 22px; width: 64.8px;"> 3591292</td>
<td style="height: 22px; width: 36px;">""</td>
<td style="height: 22px; width: 36px;">4092853</td>
<td style="height: 22px; width: 36px;">""</td>
</tr>
<tr style="height: 22px;">
<td style="height: 22px; width: 15.2px;">10</td>
<td style="height: 22px; width: 64.8px;">2368927</td>
<td style="height: 22px; width: 36px;">""</td>
<td style="height: 22px; width: 36px;">355650</td>
<td style="height: 22px; width: 36px;">""</td>
</tr>
</tbody>
</tbody>
</table>
<p>As we can see, results obtained by using different tools are not the same. It is evident that the first tool obtains better results, but - most importantly - neither the one nor the other is able to match 100% of PMID-DOI couples. So, the mapping is incomplete.</p>
<h2>Notes on expected structure of the main function</h2>
<p>In order to understand what kind of input and output to expect, we can start from the model provided by CROCI.</p>
<h2>Test Case development</h2>
<p>Reference Test Case:</p>
<h3>index/test/09_croci.py</h3>
<div class="codebg"><code><pre> import unittest
from index.coci.glob import process
from os import sep, makedirs
from os.path import exists
from shutil import rmtree
from index.storer.csvmanager import CSVManager
from index.croci.crowdsourcedcitationsource import CrowdsourcedCitationSource
from csv import DictReader
class CROCITest(unittest.TestCase):
def setUp(self):
self.input_file = "index%stest_data%scroci_dump%ssource.csv" % (sep, sep, sep)
self.citations = "index%stest_data%scroci_dump%scitations.csv" % (sep, sep, sep)
def test_citation_source(self):
ccs = CrowdsourcedCitationSource(self.input_file)
new = []
cit = ccs.get_next_citation_data()
while cit is not None:
citing, cited, creation, timespan, journal_sc, author_sc = cit
new.append({
"citing": citing,
"cited": cited,
"creation": "" if creation is None else creation,
"timespan": "" if timespan is None else timespan,
"journal_sc": "no" if journal_sc is None else journal_sc,
"author_sc": "no" if author_sc is None else author_sc
})
cit = ccs.get_next_citation_data()
with open(self.citations) as f:
old = list(DictReader(f))
self.assertEqual(new, old)</pre></code></div>
<h3>On this base, a basic idea of index/test/(n?)_noci.py</h3>
<iframe src="https://trinket.io/embed/python/221e5803ec?toggleCode=true" width="100%" height="356" frameborder="0" marginwidth="0" marginheight="0" allowfullscreen></iframe>
<div class="codebg">
<code>
<pre>
import unittest
from index.coci.glob import process #something to be developed to perform the same task but with pmids
from os import sep, makedirs #Recursive directory creation function. Like mkdir(), but makes all intermediate-level directories needed to contain the leaf directory.
from os.path import exists #used to check whether the specified path exists or not.
from shutil import rmtree #used to delete an entire directory tree, path must point to a directory (but not a symbolic link to a directory)
from index.storer.csvmanager import CSVManager #This class is able to load a simple CSV composed by two fields, 'id' and'value', and then to index all its items in a structured form so as to be easily queried. In addition, it allows one to store new information in the CSV, if needed.
from index.noci.nationalinstituteofhealthsource import NationalInstitutHealthSource #crowdsourcedcitationsource sostituito
from csv import DictReader
class NOCITest(unittest.TestCase):
def setUp(self): #The self parameter is a reference to the current instance of the class, and is used to access variables that belongs to the class.
self.input_file = "index%stest_data%snoci_dump%ssource.csv" % (sep, sep, sep) #without placeholders for the tuple format, data as provided by NIH
self.citations = "index%stest_data%snoci_dump%scitations.csv" % (sep, sep, sep) #adaptation for tuple format, with all 6 fields
def test_citation_source(self):
ns = NationalInstitutHealthSource(self.input_file) #class of nationalinstituteofhealthsource, where a version of get next citation handling pmid data will be defined.
new = []
cit = ns.get_next_citation_data_pmidversion() #will extract citational data from our input file, which is the source one, with just citing and cited
while cit is not None: #(which is: until we have citational data)
citing, cited, creation, timespan, journal_sc, author_sc = cit #related to the csv format (?) does the comma separator define the fields, so that cit becomes che full ciation divided by fields?
#we append each citational data to the new list (which will be a list of dictionaries), in the format required for the 6-elements tuple.
new.append({
"citing": citing,
"cited": cited,
"creation": "" if creation is None else creation, #in all our cases the last four fields will be "","","no","no"
"timespan": "" if timespan is None else timespan,
"journal_sc": "no" if journal_sc is None else journal_sc,
"author_sc": "no" if author_sc is None else author_sc
})
cit = ns.get_next_citation_data_pmidversion() #cit variable is assigned the value of the subsequent citational datum from input_file (source.csv)
with open(self.citations) as f: #open the file as a parameter of a function, this time the csv with the data compiled in the 6-elements tuple format
old = list(DictReader(f)) #a list of dictionaries is derived from data in citations.
self.assertEqual(new, old) #check that the lists of dictionaries derived respectively from source and from citations are the equal.
</pre>
</code>
</div>
<h2>Prompt: basic commands</h2>
<h3>General</h3>
<ul>
<li>Lists Installed Drivers (<strong>driverquery</strong>): get a full list of installed drivers in your pc (driverquery -v to obtain more information). </li>
<li><strong>ipconfig</strong>: provides your ip address + your local network.</li>
<li><strong>systeminfo</strong>: to know very basic information about your pc’s hardware, like – motherboard, processor, ram</li>
<li><strong>ping</strong>:sends packets of data to a specific IP address (or domain) on a network and then lets you know how long it took to transmit that data and get a response (ping + ip or domain).</li>
<li><strong>sfc /scannow</strong>scan and repare windown system files. But you must be run the console as an administrator</li>
<li><strong>tasklist</strong>: gets a list of all tasks running on your pc (tasklist -v). </li>
<li><strong>cd</strong>: </li>
<ol>
<li><strong>cd\</strong> to go to the top of the directory tree</li>
<li><strong>CD Folder</strong>to go to a specific folder from this drive. The subfolders must be separated by a backslash character: \.</li>
<li><strong>cd..</strong>to go one folder up.</li>
</ol>
<li>To change the drive from “C:” to “D:”, type d:</li>
<li><strong>mkdir</strong>: (Make Directory) command. mkdir Folder creates a folder.</li>
<li><strong>cls</strong>: clear screen, to clear the command prompt screen.</li>
</ul>
<p>Source: <a href="https://dev.to/iamprogrammmer/command-prompt-basic-commands-you-should-know-cmd-4aj">dev.to</a></p>
<h3>Unittest</h3>
<p> Unittest from command line in order to make tests on modules, classes or specific methods</p>
<ul>
<li>python -m unittest test_module1 test_module2</li>
<li>python -m unittest test_module.TestClass</li>