Z0Z-tools 0.5.2__py3-none-any.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.
@@ -0,0 +1,85 @@
1
+ from typing import Any, Dict, List
2
+
3
+ def stringItUp(*scrapPile: Any) -> List[str]:
4
+ """
5
+ Recursively extracts all elements from nested data structures and converts the elements to strings.
6
+ Order is not preserved.
7
+ Parameters:
8
+ *scrapPile: One or more data structures to unpack and convert to strings.
9
+ Returns:
10
+ listStrungUp: A list of string versions of all elements in the input data structure.
11
+ """
12
+ listStrungUp = []
13
+
14
+ def drill(KitKat: Any) -> None:
15
+ if isinstance(KitKat, str):
16
+ listStrungUp.append(KitKat)
17
+ elif isinstance(KitKat, (bool, bytearray, bytes, complex, float, int, memoryview, type(None))):
18
+ listStrungUp.append(str(KitKat))
19
+ elif isinstance(KitKat, dict):
20
+ for broken, piece in KitKat.items():
21
+ drill(broken)
22
+ drill(piece)
23
+ elif isinstance(KitKat, (frozenset, list, range, set, tuple)):
24
+ for kit in KitKat:
25
+ drill(kit)
26
+ elif hasattr(KitKat, '__iter__'): # Unpack other iterables
27
+ for kat in KitKat:
28
+ drill(kat)
29
+ else:
30
+ try:
31
+ sharingIsCaring = KitKat.__str__()
32
+ listStrungUp.append(sharingIsCaring)
33
+ except AttributeError:
34
+ pass
35
+ except TypeError: # "The error traceback provided indicates that there is an issue when calling the __str__ method on an object that does not have this method properly defined, leading to a TypeError."
36
+ pass
37
+ try:
38
+ for scrap in scrapPile:
39
+ drill(scrap)
40
+ except RecursionError:
41
+ listStrungUp.append(repr(scrap))
42
+ return listStrungUp
43
+
44
+ def updateExtendPolishDictionaryLists(*dictionaryLists: Dict[str, List[Any]], destroyDuplicates: bool = False, reorderLists: bool = False, \
45
+ killErroneousDataTypes: bool = False) -> Dict[str, List[Any]]:
46
+ """
47
+ Merges multiple dictionaries containing lists into a single dictionary, with options to handle duplicates,
48
+ list ordering, and erroneous data types.
49
+ Parameters:
50
+ *dictionaryLists: Variable number of dictionaries to be merged. If only one dictionary is passed, it will be processed based on the provided options.
51
+ destroyDuplicates (False): If True, removes duplicate elements from the lists. Defaults to False.
52
+ ignoreListOrdering (False): If True, sorts the lists. Defaults to False.
53
+ killErroneousDataTypes (False): If True, skips lists that cause a TypeError during merging. Defaults to False.
54
+ Returns:
55
+ ePluribusUnum: A single dictionary with merged lists based on the provided options. If only one dictionary is passed,
56
+ it will be cleaned up based on the options.
57
+ Note:
58
+ The returned value, `ePluribusUnum`, is a so-called primitive dictionary (`typing.Dict`). Furthermore, every dictionary key is a
59
+ so-called primitive string (cf. `str()`) and every dictionary value is a so-called primitive list (`typing.List`). If `dictionaryLists`
60
+ has other data types, the data types will not be preserved. That could have unexpected consequences: in some cases, for example, conversion
61
+ from the original data type to a `typing.List` will not preserve the order even if you want the order preserved.
62
+ """
63
+
64
+ ePluribusUnum: Dict[str, List[Any]] = {}
65
+
66
+ for dictionaryListTarget in dictionaryLists:
67
+ for keyName, keyValue in dictionaryListTarget.items():
68
+ try:
69
+ ImaStr = str(keyName)
70
+ ImaList = list(keyValue)
71
+ ePluribusUnum.setdefault(ImaStr, []).extend(ImaList)
72
+ except TypeError:
73
+ if killErroneousDataTypes:
74
+ continue
75
+ else:
76
+ raise
77
+
78
+ if destroyDuplicates:
79
+ for ImaStr, ImaList in ePluribusUnum.items():
80
+ ePluribusUnum[ImaStr] = list(dict.fromkeys(ImaList))
81
+ if reorderLists:
82
+ for ImaStr, ImaList in ePluribusUnum.items():
83
+ ePluribusUnum[ImaStr] = sorted(ImaList)
84
+
85
+ return ePluribusUnum
Z0Z_tools/Z0Z_io.py ADDED
@@ -0,0 +1,23 @@
1
+ from typing import Iterable, Any, Union
2
+ import os
3
+
4
+ def dataTabularTOpathFilenameDelimited(pathFilename: Union[str, os.PathLike[Any]], tableRows: Iterable[Iterable[Any]], \
5
+ tableColumns: Iterable[Any], delimiterOutput: str = '\t') -> None:
6
+ """
7
+ Writes tabular data to a delimited file. This is a low-quality function: you'd probably be better off with something else.
8
+ Parameters:
9
+ pathFilename: The path and filename where the data will be written.
10
+ tableRows: The rows of the table, where each row is a list of strings or floats.
11
+ tableColumns: The column headers for the table.
12
+ delimiterOutput (tab): The delimiter to use in the output file. Defaults to *tab*.
13
+ Returns:
14
+ None:
15
+
16
+ This function still exists because I have not refactored `analyzeAudio.analyzeAudioListPathFilenames()`. The structure of
17
+ that function's returned data is easily handled by this function. See https://github.com/hunterhogan/analyzeAudio
18
+ """
19
+ with open(pathFilename, 'w', newline='') as writeStream:
20
+ writeStream.write(delimiterOutput.join(tableColumns) + '\n')
21
+
22
+ for row in tableRows:
23
+ writeStream.write(delimiterOutput.join(map(str, row)) + '\n')
@@ -0,0 +1,123 @@
1
+ from numpy.typing import NDArray
2
+ from typing import Any, BinaryIO, Dict, List, Sequence, Tuple, Union
3
+ import io
4
+ import numpy
5
+ import os
6
+ import pathlib
7
+ import samplerate
8
+ import soundfile
9
+
10
+ def loadWaveforms(listPathFilenames: Union[Sequence[str], Sequence[os.PathLike[str]]], sampleRate: int = 44100) -> NDArray[numpy.float32]:
11
+ """
12
+ Load a list of audio files into a single array.
13
+ Parameters:
14
+ listPathFilenames: List of file paths to the audio files.
15
+ sampleRate (44100): Target sample rate for the waveforms; the function will resample if necessary. Defaults to 44100.
16
+ Returns:
17
+ arrayWaveforms: A single NumPy array of shape (COUNTchannels, COUNTsamplesMaximum, COUNTwaveforms)
18
+ """
19
+ axisOrderMapping: Dict[str, int] = {'indexingAxis': -1, 'axisTime': -2, 'axisChannels': 0}
20
+ axesSizes: Dict[str, int] = {keyName: 1 for keyName in axisOrderMapping.keys()}
21
+ COUNTaxes: int = len(axisOrderMapping)
22
+ listShapeIndexToSize: List[int] = [9001] * COUNTaxes
23
+
24
+ COUNTwaveforms: int = len(listPathFilenames)
25
+ axesSizes['indexingAxis'] = COUNTwaveforms
26
+ COUNTchannels: int = 2
27
+ axesSizes['axisChannels'] = COUNTchannels
28
+
29
+ listCOUNTsamples: List[int] = []
30
+ axisTime: int = 0
31
+
32
+ for pathFilename in listPathFilenames:
33
+ with soundfile.SoundFile(pathFilename) as readSoundFile:
34
+ sampleRateSoundFile: int = readSoundFile.samplerate
35
+ waveform: NDArray[numpy.float32] = readSoundFile.read(dtype='float32', always_2d=True).astype(numpy.float32)
36
+ if sampleRateSoundFile != sampleRate:
37
+ waveform = resampleWaveform(waveform, sampleRate, sampleRateSoundFile)
38
+ listCOUNTsamples.append(waveform.shape[axisTime])
39
+
40
+ COUNTsamplesMaximum: int = max(listCOUNTsamples)
41
+ axesSizes['axisTime'] = COUNTsamplesMaximum
42
+
43
+ for keyName, axisSize in axesSizes.items():
44
+ axisNormalized: int = (axisOrderMapping[keyName] + COUNTaxes) % COUNTaxes
45
+ listShapeIndexToSize[axisNormalized] = axisSize
46
+ tupleShapeArray: Tuple[int, ...] = tuple(listShapeIndexToSize)
47
+
48
+ # `numpy.zeros` so that shorter waveforms are safely padded with zeros
49
+ arrayWaveforms: NDArray[numpy.float32] = numpy.zeros(tupleShapeArray, dtype=numpy.float32)
50
+
51
+ for index in range(COUNTwaveforms):
52
+ with soundfile.SoundFile(listPathFilenames[index]) as readSoundFile:
53
+ sampleRateSoundFile: int = readSoundFile.samplerate
54
+ waveform: NDArray[numpy.float32] = readSoundFile.read(dtype='float32', always_2d=True).astype(numpy.float32)
55
+
56
+ if sampleRateSoundFile != sampleRate:
57
+ waveform = resampleWaveform(waveform, sampleRate, sampleRateSoundFile)
58
+
59
+ COUNTsamples: int = waveform.shape[axisTime]
60
+ arrayWaveforms[:, 0:COUNTsamples, index] = waveform.T
61
+
62
+ return arrayWaveforms
63
+
64
+ def readAudioFile(pathFilename: Union[str, os.PathLike[Any], BinaryIO], sampleRate: int = 44100) -> NDArray[numpy.float32]:
65
+ """
66
+ Reads an audio file and returns its data as a NumPy array. Mono is always converted to stereo.
67
+
68
+ Parameters:
69
+ pathFilename: The path to the audio file.
70
+ sampleRate (44100): The sample rate to use when reading the file. Defaults to 44100.
71
+
72
+ Returns:
73
+ waveform: The audio data in an array shaped (channels, samples).
74
+ """
75
+ with soundfile.SoundFile(pathFilename) as readStream:
76
+ sampleRateSource: int = readStream.samplerate
77
+ waveform: NDArray[numpy.float32] = readStream.read(dtype='float32', always_2d=True).astype(numpy.float32)
78
+ waveform = resampleWaveform(waveform, sampleRateDesired=sampleRate, sampleRateSource=sampleRateSource)
79
+ return waveform.T
80
+
81
+ def resampleWaveform(waveform: NDArray[numpy.float32], sampleRateDesired: int, sampleRateSource: int) -> NDArray[numpy.float32]:
82
+ """
83
+ Resamples the waveform to the desired sample rate.
84
+
85
+ Parameters:
86
+ waveform: The input audio data.
87
+ sampleRateDesired: The desired sample rate.
88
+ sampleRateSource: The original sample rate of the waveform.
89
+
90
+ Returns:
91
+ waveformResampled: The resampled waveform.
92
+ """
93
+ if sampleRateSource != sampleRateDesired:
94
+ converter: str = 'sinc_best'
95
+ ratio: float = sampleRateDesired / sampleRateSource
96
+ waveformResampled: NDArray[numpy.float32] = samplerate.resample(waveform, ratio, converter)
97
+ return waveformResampled
98
+ else:
99
+ return waveform
100
+
101
+ def writeWav(pathFilename: Union[str, os.PathLike[Any], io.IOBase], waveform: NDArray[Any], sampleRate: int = 44100) -> None:
102
+ """
103
+ Writes a waveform to a WAV file.
104
+
105
+ Parameters:
106
+ pathFilename: The path and filename where the WAV file will be saved.
107
+ waveform: The waveform data to be written to the WAV file. The waveform should be in the shape (channels, samples).
108
+ sampleRate (44100): The sample rate of the waveform. Defaults to 44100 Hz.
109
+
110
+ Notes:
111
+ The function will create any necessary directories if they do not exist.
112
+ The function will overwrite the file if it already exists without prompting or informing the user.
113
+
114
+ Returns:
115
+ None:
116
+
117
+ """
118
+ if not isinstance(pathFilename, io.IOBase):
119
+ try:
120
+ pathlib.Path(pathFilename).parent.mkdir(parents=True, exist_ok=True)
121
+ except OSError:
122
+ pass
123
+ soundfile.write(file=pathFilename, data=waveform.T, samplerate=sampleRate, subtype='FLOAT', format='WAV')
Z0Z_tools/__init__.py ADDED
@@ -0,0 +1,19 @@
1
+ __author__ = "Hunter Hogan"
2
+ __version__ = "0.5.2"
3
+
4
+ from Z0Z_tools.pipAnything import installPackageTarget, makeListRequirementsFromRequirementsFile
5
+ from Z0Z_tools.Z0Z_dataStructure import stringItUp, updateExtendPolishDictionaryLists
6
+ from Z0Z_tools.Z0Z_io import dataTabularTOpathFilenameDelimited
7
+ from Z0Z_tools.Z0Z_ioAudio import writeWav, readAudioFile, loadWaveforms
8
+
9
+ __all__ = [
10
+ 'dataTabularTOpathFilenameDelimited',
11
+ 'installPackageTarget',
12
+ 'loadWaveforms',
13
+ 'makeListRequirementsFromRequirementsFile',
14
+ 'readAudioFile',
15
+ 'stringItUp',
16
+ 'updateExtendPolishDictionaryLists',
17
+ 'writeWav',
18
+ ]
19
+
@@ -0,0 +1,156 @@
1
+ """
2
+ Functions:
3
+ - installPackageTarget: Tries to trick pip into installing the package from a given directory.
4
+ - makeListRequirementsFromRequirementsFile: Reads a requirements.txt file, discards anything it couldn't understand, and creates a list of packages.
5
+
6
+ Usage:
7
+ from pipAnything import installPackageTarget
8
+ installPackageTarget('path/to/packageTarget')
9
+
10
+ pip will attempt to install requirements.txt, but don't rely on dependencies being installed.
11
+ """
12
+
13
+ from packaging.requirements import Requirement
14
+ from typing import List, Union
15
+ import os
16
+ import pathlib
17
+ import subprocess
18
+ import sys
19
+ import tempfile
20
+
21
+ def makeListRequirementsFromRequirementsFile(*pathFilenames: Union[str, os.PathLike[str]]) -> List[str]:
22
+ """
23
+ Reads one or more requirements files and extracts valid package requirements.
24
+ Parameters:
25
+ *pathFilenames: One or more paths to requirements files.
26
+ Returns:
27
+ listRequirements: A list of unique, valid package requirements found in the provided files.
28
+ The function performs the following steps:
29
+ 1. Iterates over each provided file path.
30
+ 2. Checks if the file exists.
31
+ 3. Reads the file line by line, removing comments and trimming whitespace.
32
+ 4. Skips lines that are empty or contain spaces/tabs after sanitization.
33
+ 5. Validates if the sanitized line is a valid requirement.
34
+ 6. Collects valid requirements and removes duplicates before returning the list.
35
+ """
36
+ listRequirements = []
37
+
38
+ for pathFilename in pathFilenames:
39
+ if pathlib.Path(pathFilename).exists():
40
+ try:
41
+ filesystemObjectRead = open(pathFilename, 'r')
42
+ for commentedLine in filesystemObjectRead:
43
+ sanitizedLine = commentedLine.split('#')[0].strip() # Remove comments and trim whitespace
44
+
45
+ # Skip lines that are empty or contain spaces/tabs after sanitization
46
+ if "\t" in sanitizedLine or " " in sanitizedLine or not sanitizedLine:
47
+ continue
48
+
49
+ # Validate if it's a valid requirement
50
+ try:
51
+ Requirement(sanitizedLine)
52
+ listRequirements.append(sanitizedLine)
53
+ except:
54
+ pass # Skip invalid requirement lines
55
+ finally:
56
+ filesystemObjectRead.close()
57
+
58
+ return sorted(set(listRequirements)) # Remove duplicates
59
+
60
+ def make_setupDOTpy(relativePathPackage: Union[str, os.PathLike[str]], listRequirements: List[str]) -> str:
61
+ """
62
+ Generates setup.py file content for installing the package.
63
+
64
+ Parameters:
65
+ relativePathPackage: The relative path to the package directory.
66
+ listRequirements: A list of requirements to be included in install_requires.
67
+
68
+ Returns:
69
+ str: The setup.py content to be written to a file.
70
+ """
71
+ return rf"""
72
+ import os
73
+ from setuptools import setup, find_packages
74
+
75
+ setup(
76
+ name='{pathlib.Path(relativePathPackage).name}',
77
+ version='0.0.0',
78
+ packages=find_packages(where=r'{relativePathPackage}'),
79
+ package_dir={{'': r'{relativePathPackage}'}},
80
+ install_requires={listRequirements},
81
+ include_package_data=True,
82
+ )
83
+ """
84
+
85
+ def installPackageTarget(pathPackageTarget: Union[str, os.PathLike[str]]) -> None:
86
+ """
87
+ Installs a package by creating a temporary setup.py and tricking pip into installing it.
88
+
89
+ Parameters:
90
+ pathPackageTarget: The directory path of the package to be installed.
91
+ """
92
+ filenameRequirementsHARDCODED = pathlib.Path('requirements.txt')
93
+ filenameRequirements = pathlib.Path(filenameRequirementsHARDCODED)
94
+
95
+ pathPackage = pathlib.Path(pathPackageTarget).resolve()
96
+ pathSystemTemporary = pathlib.Path(tempfile.mkdtemp())
97
+ pathFilename_setupDOTpy = pathSystemTemporary / 'setup.py'
98
+
99
+ pathFilenameRequirements = pathPackage / filenameRequirements
100
+ listRequirements = makeListRequirementsFromRequirementsFile(pathFilenameRequirements)
101
+
102
+ # Try-finally block for file handling: with-as doesn't always work
103
+ writeStream = None
104
+ try:
105
+ writeStream = pathFilename_setupDOTpy.open(mode='w')
106
+ relativePathPackage = pathPackage.relative_to(pathSystemTemporary, walk_up=True).as_posix()
107
+ writeStream.write(make_setupDOTpy(relativePathPackage, listRequirements))
108
+ finally:
109
+ if writeStream:
110
+ writeStream.close()
111
+
112
+ # Run pip to install the package from the temporary directory
113
+ subprocessPython = subprocess.Popen(
114
+ # `pip` needs a RELATIVE PATH, not an absolute path, and not a path+filename.
115
+ args=[sys.executable, '-m', 'pip', 'install', str(pathSystemTemporary)],
116
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
117
+ )
118
+
119
+ # Output the subprocess stdout in real-time
120
+ if subprocessPython.stdout:
121
+ for lineStdout in subprocessPython.stdout:
122
+ print(lineStdout, end="")
123
+
124
+ subprocessPython.wait()
125
+
126
+ # Clean up by removing setup.py
127
+ pathFilename_setupDOTpy.unlink()
128
+
129
+ def everyone_knows_what___main___is() -> None:
130
+ """A rudimentary CLI for the module.
131
+ call `installPackageTarget` from other modules."""
132
+ packageTarget = sys.argv[1] if len(sys.argv) > 1 else ''
133
+ pathPackageTarget = pathlib.Path(packageTarget)
134
+ if not pathPackageTarget.is_dir() or len(sys.argv) != 2:
135
+ namespaceModule = pathlib.Path(__file__).stem
136
+ namespacePackage = pathlib.Path(__file__).parent.stem
137
+ print(f"\n{namespaceModule} says, 'That didn't work. Try again?'\n\n"
138
+ f"Usage:\tpython -m {namespacePackage}.{namespaceModule} <packageTarget>\n"
139
+ f"\t<packageTarget> is a path to a directory with Python modules\n"
140
+ f"\tExample: python -m {namespacePackage}.{namespaceModule} '{pathlib.PurePath('path' ,'to', 'Z0Z_tools')}'")
141
+ # What is `-m`? Obviously, `-m` creates a namespace for the module, which is obviously necessary, except when it isn't.
142
+ sys.exit(1)
143
+
144
+ installPackageTarget(pathPackageTarget)
145
+ print(f"\n{pathlib.Path(__file__).stem} finished trying to trick pip into installing {pathPackageTarget.name}. Did it work?")
146
+
147
+ def readability_counts() -> None:
148
+ """Brings the snark."""
149
+ everyone_knows_what___main___is()
150
+
151
+ def main() -> None:
152
+ """Jabs subtly."""
153
+ readability_counts()
154
+
155
+ if __name__ == "__main__":
156
+ main()
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.1
2
+ Name: Z0Z_tools
3
+ Version: 0.5.2
4
+ Summary: Audio processing, data structure, and package management tools.
5
+ Project-URL: Homepage, https://github.com/hunterhogan/Z0Z_tools
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: numpy
9
+ Requires-Dist: packaging
10
+ Requires-Dist: samplerate
11
+ Requires-Dist: soundfile
12
+
13
+ # Z0Z_tools
14
+
15
+ "Z0Z_"- is a placeholder, and a Z0Z_tool is at best, a prototype.
16
+
17
+ ## Install an arbitrary package with `pipAnything`
18
+
19
+ Try to install a package that doesn't have installation files.
20
+
21
+ ```sh
22
+ python -m Z0Z_tools.pipAnything <pathPackage>
23
+ ```
24
+
25
+ ## Unpack and convert elements to `str` types with `stringItUp`
26
+
27
+ ## Merge and/or lightly clean a dictionary of lists with `updateExtendPolishDictionaryLists`
28
+
29
+ - Merges multiple dictionaries of lists into a single dictionary.
30
+ - Optionally remove duplicates each list.
31
+ - Optionally sort each list.
32
+ - Optionally delete data that won't merge.
33
+
34
+ ## Basic read/write WAV files with `readAudioFile` and `writeWav`
35
+
36
+ The only option is the sample rate.
37
+
38
+ ## Use `loadWaveforms` to create one array of waveforms from multiple files
39
+
40
+ ## Install this package
41
+
42
+ ### From Github
43
+
44
+ ```sh
45
+ pip install Z0Z_tools@git+https://github.com/hunterhogan/Z0Z_tools.git
46
+ ```
47
+
48
+ ### From a local directory
49
+
50
+ #### Windows
51
+
52
+ ```powershell
53
+ git clone https://github.com/hunterhogan/Z0Z_tools.git \path\to\Z0Z_tools
54
+ pip install Z0Z_tools@file:\path\to\Z0Z_tools
55
+ ```
56
+
57
+ #### POSIX
58
+
59
+ ```bash
60
+ git clone https://github.com/hunterhogan/Z0Z_tools.git /path/to/Z0Z_tools
61
+ pip install Z0Z_tools@file:/path/to/Z0Z_tools
62
+ ```
63
+
64
+ ## Install updates
65
+
66
+ ```sh
67
+ pip install --upgrade Z0Z_tools@git+https://github.com/hunterhogan/Z0Z_tools.git
68
+ ```
@@ -0,0 +1,12 @@
1
+ Z0Z_tools/Z0Z_dataStructure.py,sha256=_JAMowiDupWVTbRgonau8O8UTvZDHuNTk61EbX-a3R4,4098
2
+ Z0Z_tools/Z0Z_io.py,sha256=OPwSM04xhyLTuGwhAR73i4UxmMC9tGS-z4d1HstXjUk,1229
3
+ Z0Z_tools/Z0Z_ioAudio.py,sha256=L8F23JpGmG8KE-tDiRQsBgoJF2bPHYclk-K2w6CwzAU,5465
4
+ Z0Z_tools/__init__.py,sha256=U6auRjRMpVKba_awePT9ipumvmnK6UB185_gHBQBucM,622
5
+ Z0Z_tools/pipAnything.py,sha256=HenP4K_fBAdurrRGgKCFkS4HIqFNj6guw_BZl2tkjMU,6380
6
+ unittests/test_Z0Z_dataStructure.py,sha256=mInwhLhX_9jaLy8IMPSt4Vfec9J14ntnbjHEvrTqeNo,14841
7
+ unittests/test_ioAudio.py,sha256=nyOu_oY74uPQIwpR-JkhEJ1IinLjIt2_TiUmG-7qBgA,2736
8
+ unittests/test_pipAnything.py,sha256=55QG_HoDVQQT9uvB43yLxVz-fY6rugv4ODcmsd9a_oU,2668
9
+ Z0Z_tools-0.5.2.dist-info/METADATA,sha256=uZK7cJTYpumIeF3invq3pfgvbU2pcIAF-qtagarLOt4,1687
10
+ Z0Z_tools-0.5.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
11
+ Z0Z_tools-0.5.2.dist-info/top_level.txt,sha256=0QGn7IRzNFffddo0Wg128tqn55DbM2H47940hEgqgFg,20
12
+ Z0Z_tools-0.5.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.6.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ Z0Z_tools
2
+ unittests
@@ -0,0 +1,340 @@
1
+ from decimal import Decimal
2
+ from fractions import Fraction
3
+ from itertools import count, islice
4
+ from Z0Z_tools.Z0Z_dataStructure import updateExtendPolishDictionaryLists, stringItUp
5
+ import datetime
6
+ import numpy
7
+ import unittest
8
+ import uuid
9
+
10
+ class TestStringItUp(unittest.TestCase):
11
+
12
+ def test_empty_input(self):
13
+ self.assertEqual(stringItUp(), [])
14
+
15
+ def test_with_bytearray(self):
16
+ self.assertEqual(stringItUp(bytearray(b"bytearray")), ["bytearray(b'bytearray')"])
17
+
18
+ def test_with_generator(self):
19
+ def gen():
20
+ for i in range(3):
21
+ yield i
22
+ self.assertEqual(stringItUp(gen()), ['0', '1', '2'])
23
+
24
+ def test_with_infinite_iterator(self):
25
+ infinite_gen = count()
26
+ limited_gen = islice(infinite_gen, 5)
27
+ self.assertEqual(stringItUp(limited_gen), ['0', '1', '2', '3', '4'])
28
+
29
+ def test_with_object_with_custom_iter(self):
30
+ class CustomIter:
31
+ def __iter__(self):
32
+ return iter([1, 2, 3])
33
+ self.assertEqual(stringItUp(CustomIter()), ['1', '2', '3'])
34
+
35
+ def test_with_recursive_structure(self):
36
+ chicken_tikka_masala = []
37
+ chicken_tikka_masala.append(chicken_tikka_masala)
38
+ self.assertEqual(stringItUp(chicken_tikka_masala), ['[[...]]'])
39
+
40
+ def test_with_recursive_structure2(self):
41
+ chicken_tikka_masala = []
42
+ chicken_tikka_masala.append(chicken_tikka_masala)
43
+ self.assertEqual(stringItUp([chicken_tikka_masala, 'wazzup']), ["[[[...]], 'wazzup']"])
44
+
45
+ def test_with_nan_and_inf(self):
46
+ self.assertEqual(stringItUp(float('nan'), float('inf')), ['nan', 'inf'])
47
+
48
+ def test_with_large_numbers(self):
49
+ large_number = 10**100
50
+ self.assertEqual(stringItUp(large_number), [str(large_number)])
51
+
52
+ def test_with_decimal(self):
53
+ self.assertEqual(stringItUp(Decimal('1.1')), ['1.1'])
54
+
55
+ def test_with_fraction(self):
56
+ self.assertEqual(stringItUp(Fraction(1, 3)), ['1/3'])
57
+
58
+ def test_with_dates(self):
59
+ date = datetime.date(2021, 1, 1)
60
+ self.assertEqual(stringItUp(date), ['2021-01-01'])
61
+
62
+ def test_with_times(self):
63
+ time = datetime.time(12, 34, 56)
64
+ self.assertEqual(stringItUp(time), ['12:34:56'])
65
+
66
+ def test_with_datetime(self):
67
+ dt = datetime.datetime(2021, 1, 1, 12, 34, 56)
68
+ self.assertEqual(stringItUp(dt), ['2021-01-01 12:34:56'])
69
+
70
+ def test_with_uuid(self):
71
+ my_uuid = uuid.uuid4()
72
+ self.assertEqual(stringItUp(my_uuid), [str(my_uuid)])
73
+
74
+ def test_with_memoryview(self):
75
+ result = stringItUp(memoryview(b"memoryview"))
76
+ expected_prefix = "<memory at 0x"
77
+ self.assertTrue(result[0].startswith(expected_prefix))
78
+
79
+ def test_empty_iterable_types(self):
80
+ self.assertEqual(stringItUp([], (), set()), [])
81
+
82
+ def test_mixed_nested_iterables(self):
83
+ data = [1, (2, {3, "four"}), {"five": [6, 7]}]
84
+ self.assertCountEqual(stringItUp(data), ["1", "2", "3", "four", "five", "6", "7"])
85
+
86
+ def test_large_data(self):
87
+ large_list = list(range(1000))
88
+ result = stringItUp(large_list)
89
+ self.assertEqual(len(result), 1000)
90
+ for i in range(1000):
91
+ self.assertEqual(result[i], str(i))
92
+
93
+ class TestUpdateExtendDictionaryLists(unittest.TestCase):
94
+
95
+ def test_with_mixed_types_in_values(self):
96
+ primus = {'a': [1, 'two'], 'b': [True, None]}
97
+ secundus = {'a': [3.14, 'four'], 'b': [False, 'none']}
98
+ expected = {
99
+ 'a': [1, 'two', 3.14, 'four'],
100
+ 'b': [True, None, False, 'none']
101
+ }
102
+ result = updateExtendPolishDictionaryLists(primus, secundus)
103
+ self.assertEqual(result, expected)
104
+
105
+ def test_with_non_string_keys(self):
106
+ primus = {None: [3], True: [2]}
107
+ secundus = {1: [1], (4, 5): [4]}
108
+ expected ={'(4, 5)': [4], '1': [1], 'None': [3], 'True': [2]}
109
+ result = updateExtendPolishDictionaryLists(primus, secundus) # type: ignore
110
+ self.assertEqual(result, expected)
111
+
112
+ def test_with_conflicting_data_types(self):
113
+ primus = {'a': 1, 'b': 2}
114
+ secundus = {'a': 3, 'c': 4}
115
+ with self.assertRaises(TypeError):
116
+ result = updateExtendPolishDictionaryLists(primus, secundus) # type: ignore
117
+
118
+ def test_with_kill_erroneous_data_types(self):
119
+ primus = {'a': [1, 2], 'b': [3, 4]}
120
+ secundus = {'a': 3, 'c': 4}
121
+ expected = {'a': [1, 2], 'b': [3, 4]}
122
+ result = updateExtendPolishDictionaryLists(primus, secundus, killErroneousDataTypes=True) # type: ignore
123
+ self.assertEqual(result, expected)
124
+
125
+ def test_basic_functionality(self):
126
+ primus = {'a': [3, 1], 'b': [2]}
127
+ secundus = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
128
+ expected = {'a': [3, 1, 9, 6, 1, 22, 3], 'b': [2, 111111, 2, 3]}
129
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=False, reorderLists=False)
130
+ self.assertEqual(result, expected)
131
+
132
+ def test_ignore_list_ordering(self):
133
+ primus = {'a': [3, 1], 'b': [2]}
134
+ secundus = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
135
+ expected = {'a': [1, 1, 3, 3, 6, 9, 22], 'b': [2, 2, 3, 111111]}
136
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=False, reorderLists=True)
137
+ self.assertEqual(result, expected)
138
+
139
+ def test_destroy_duplicates(self):
140
+ primus = {'a': [3, 1], 'b': [2]}
141
+ secundus = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
142
+ expected = {'a': [3, 1, 9, 6, 22], 'b': [2, 111111, 3]}
143
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=True, reorderLists=False)
144
+ self.assertEqual(result, expected)
145
+
146
+ def test_single_dictionary_secundus2(self):
147
+ secundus = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
148
+ expected = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
149
+ result = updateExtendPolishDictionaryLists({}, secundus, destroyDuplicates=False, reorderLists=False)
150
+ self.assertEqual(result, expected)
151
+
152
+ def test_single_dictionary_secundus_ignore_list_ordering2(self):
153
+ secundus = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
154
+ expected = {'a': [1, 3, 6, 9, 22], 'b': [2, 3, 111111]}
155
+ result = updateExtendPolishDictionaryLists({}, secundus, destroyDuplicates=False, reorderLists=True)
156
+ self.assertEqual(result, expected)
157
+
158
+ def test_single_dictionary_secundus_destroy_duplicates2(self):
159
+ secundus = {'a': [9, 6, 1, 22, 3, 9], 'b': [111111, 2, 3, 2]}
160
+ expected = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
161
+ result = updateExtendPolishDictionaryLists({}, secundus, destroyDuplicates=True, reorderLists=False)
162
+ self.assertEqual(result, expected)
163
+
164
+ def test_single_dictionary_secundus_destroy_duplicates_ignore_list_ordering2(self):
165
+ secundus = {'a': [9, 6, 1, 22, 3, 9], 'b': [111111, 2, 3, 2]}
166
+ expected = {'a': [1, 3, 6, 9, 22], 'b': [2, 3, 111111]}
167
+ result = updateExtendPolishDictionaryLists({}, secundus, destroyDuplicates=True, reorderLists=True)
168
+ self.assertEqual(result, expected)
169
+
170
+ def test_empty_dictionaries(self):
171
+ primus = {}
172
+ secundus = {}
173
+ expected = {}
174
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=False, reorderLists=False)
175
+ self.assertEqual(result, expected)
176
+
177
+ def test_empty_and_non_empty_dictionary(self):
178
+ primus = {}
179
+ secundus = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
180
+ expected = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
181
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=False, reorderLists=False)
182
+ self.assertEqual(result, expected)
183
+
184
+ def test_non_empty_and_empty_dictionary(self):
185
+ primus = {'a': [3, 1], 'b': [2]}
186
+ secundus = {}
187
+ expected = {'a': [3, 1], 'b': [2]}
188
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=False, reorderLists=False)
189
+ self.assertEqual(result, expected)
190
+
191
+ def test_empty_dictionaries_with_options(self):
192
+ primus = {}
193
+ secundus = {}
194
+ expected = {}
195
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=True, reorderLists=True)
196
+ self.assertEqual(result, expected)
197
+
198
+ def test_single_empty_dictionary(self):
199
+ primus = {}
200
+ expected = {}
201
+ result = updateExtendPolishDictionaryLists(primus, destroyDuplicates=False, reorderLists=False)
202
+ self.assertEqual(result, expected)
203
+
204
+ def test_single_empty_dictionary_with_options(self):
205
+ primus = {}
206
+ expected = {}
207
+ result = updateExtendPolishDictionaryLists(primus, destroyDuplicates=True, reorderLists=True)
208
+ self.assertEqual(result, expected)
209
+
210
+ def test_single_dictionary_primus(self):
211
+ primus = {'a': [3, 1], 'b': [2]}
212
+ expected = {'a': [3, 1], 'b': [2]}
213
+ result = updateExtendPolishDictionaryLists(primus, destroyDuplicates=False, reorderLists=False)
214
+ self.assertEqual(result, expected)
215
+
216
+ def test_single_dictionary_primus_ignore_list_ordering_variant(self):
217
+ primus = {'a': [3, 1], 'b': [2]}
218
+ expected = {'a': [1, 3], 'b': [2]}
219
+ result = updateExtendPolishDictionaryLists(primus, destroyDuplicates=False, reorderLists=True)
220
+ self.assertEqual(result, expected)
221
+
222
+ def test_single_dictionary_primus_destroy_duplicates_ignore_list_ordering_variant(self):
223
+ primus = {'a': [3, 1, 3], 'b': [2, 2]}
224
+ expected = {'a': [3, 1], 'b': [2]}
225
+ result = updateExtendPolishDictionaryLists(primus, destroyDuplicates=True, reorderLists=False)
226
+ self.assertEqual(result, expected)
227
+
228
+ def test_single_dictionary_primus_destroy_duplicates_ignore_list_ordering(self):
229
+ primus = {'a': [3, 1, 3], 'b': [2, 2]}
230
+ expected = {'a': [1, 3], 'b': [2]}
231
+ result = updateExtendPolishDictionaryLists(primus, destroyDuplicates=True, reorderLists=True)
232
+ self.assertEqual(result, expected)
233
+
234
+ def test_single_dictionary_secundus(self):
235
+ secundus = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
236
+ expected = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
237
+ result = updateExtendPolishDictionaryLists(secundus, destroyDuplicates=False, reorderLists=False)
238
+ self.assertEqual(result, expected)
239
+
240
+ def test_single_dictionary_secundus_ignore_list_ordering(self):
241
+ secundus = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
242
+ expected = {'a': [1, 3, 6, 9, 22], 'b': [2, 3, 111111]}
243
+ result = updateExtendPolishDictionaryLists(secundus, destroyDuplicates=False, reorderLists=True)
244
+ self.assertEqual(result, expected)
245
+
246
+ def test_single_dictionary_secundus_destroy_duplicates(self):
247
+ secundus = {'a': [9, 6, 1, 22, 3, 9], 'b': [111111, 2, 3, 2]}
248
+ expected = {'a': [9, 6, 1, 22, 3], 'b': [111111, 2, 3]}
249
+ result = updateExtendPolishDictionaryLists(secundus, destroyDuplicates=True, reorderLists=False)
250
+ self.assertEqual(result, expected)
251
+
252
+ def test_single_dictionary_secundus_destroy_duplicates_ignore_list_ordering(self):
253
+ secundus = {'a': [9, 6, 1, 22, 3, 9], 'b': [111111, 2, 3, 2]}
254
+ expected = {'a': [1, 3, 6, 9, 22], 'b': [2, 3, 111111]}
255
+ result = updateExtendPolishDictionaryLists(secundus, destroyDuplicates=True, reorderLists=True)
256
+ self.assertEqual(result, expected)
257
+
258
+ def test_with_sets(self):
259
+ primus = {'a': {3, 1}, 'b': {2}}
260
+ secundus = {'a': {9, 6, 1, 22, 3}, 'b': {111111, 2, 3}}
261
+ expected = {'a': [3, 1, 9, 6, 22], 'b': [2, 111111, 3]}
262
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=True, reorderLists=False) # type: ignore
263
+ self.assertCountEqual(result['a'], expected['a'])
264
+
265
+ def test_with_tuples(self):
266
+ primus = {'a': (3, 1), 'b': (2,)}
267
+ secundus = {'a': (9, 6, 1, 22, 3), 'b': (111111, 2, 3)}
268
+ expected = {'a': [3, 1, 9, 6, 1, 22, 3], 'b': [2, 111111, 2, 3]}
269
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=False, reorderLists=False)
270
+ self.assertEqual(result, expected)
271
+
272
+ def test_with_ndarray(self):
273
+ primus = {'a': numpy.array([3, 1]), 'b': numpy.array([2])}
274
+ secundus = {'a': numpy.array([9, 6, 1, 22, 3]), 'b': numpy.array([111111, 2, 3])}
275
+ expected = {'a': [3, 1, 9, 6, 1, 22, 3], 'b': [2, 111111, 2, 3]}
276
+ result = updateExtendPolishDictionaryLists(primus, secundus, destroyDuplicates=False, reorderLists=False) # type: ignore
277
+ self.assertEqual(result, expected)
278
+
279
+ def test_empty_input(self):
280
+ self.assertEqual(stringItUp(), [])
281
+
282
+ def test_single_string(self):
283
+ self.assertEqual(stringItUp("hello"), ["hello"])
284
+
285
+ def test_single_integer(self):
286
+ self.assertEqual(stringItUp(123), ["123"])
287
+
288
+ def test_single_float(self):
289
+ self.assertEqual(stringItUp(3.14), ["3.14"])
290
+
291
+ def test_single_list(self):
292
+ self.assertCountEqual(stringItUp([1, 2, "three"]), ["1", "2", "three"])
293
+
294
+ def test_single_tuple(self):
295
+ self.assertCountEqual(stringItUp((1, 2, "three")), ["1", "2", "three"])
296
+
297
+ def test_single_set(self):
298
+ self.assertCountEqual(stringItUp({1, 2, "three"}), ["1", "2", "three"])
299
+
300
+ def test_single_dict(self):
301
+ self.assertCountEqual(stringItUp({"a": 1, "b": "two"}), ["a", "1", "b", "two"])
302
+
303
+ def test_nested_list(self):
304
+ self.assertCountEqual(stringItUp([1, [2, "three"], 4]), ["1", "2", "three", "4"])
305
+
306
+ def test_nested_tuple(self):
307
+ self.assertCountEqual(stringItUp((1, (2, "three"), 4)), ["1", "2", "three", "4"])
308
+
309
+ def test_nested_set(self):
310
+ self.assertCountEqual(stringItUp({1, frozenset({2, "three"}), 4}), ["1", "2", "three", "4"])
311
+
312
+ def test_nested_dict(self):
313
+ self.assertCountEqual(stringItUp({"a": 1, "b": {"c": 2, "d": "three"}}), ["a", "1", "b", "c", "2", "d", "three"])
314
+
315
+ def test_mixed_data_types(self):
316
+ self.assertCountEqual(stringItUp(1, "two", [3, "four"], {"five": 5}), ["1", "two", "3", "four", "five", "5"])
317
+
318
+ def test_with_numpy_array(self):
319
+ self.assertCountEqual(stringItUp(numpy.array([1, 2, 3])), ["1", "2", "3"])
320
+
321
+ def test_with_custom_object(self):
322
+ class MyObject:
323
+ def __str__(self):
324
+ return "MyObject"
325
+ self.assertEqual(stringItUp(MyObject()), ["MyObject"])
326
+
327
+ def test_with_none(self):
328
+ self.assertEqual(stringItUp(None), ["None"])
329
+
330
+ def test_with_boolean(self):
331
+ self.assertCountEqual(stringItUp(True, False), ["True", "False"])
332
+
333
+ def test_with_complex_number(self):
334
+ self.assertEqual(stringItUp(1+2j), ["(1+2j)"])
335
+
336
+ def test_with_bytes(self):
337
+ self.assertEqual(stringItUp(b"bytes"), ["b'bytes'"])
338
+
339
+ if __name__ == '__main__':
340
+ unittest.main()
@@ -0,0 +1,59 @@
1
+ from Z0Z_tools import readAudioFile, loadWaveforms
2
+ import numpy
3
+ import pathlib
4
+ import unittest
5
+
6
+ class TestReadAudioFile(unittest.TestCase):
7
+
8
+ def setUp(self):
9
+ self.test_data_dir = pathlib.Path("unittests/dataSamples")
10
+ self.mono_file = self.test_data_dir / "testWooWooMono16kHz32integerClipping9sec.wav"
11
+ self.stereo_file = self.test_data_dir / "testSine2ch5sec.wav"
12
+ self.non_audio_file = self.test_data_dir / "testVideo11sec.mkv"
13
+
14
+ def test_read_mono_audio_file(self):
15
+ waveform = readAudioFile(self.mono_file)
16
+ self.assertIsInstance(waveform, numpy.ndarray)
17
+ self.assertEqual(waveform.ndim, 2) # Mono should have 1 dimension
18
+
19
+ def test_read_stereo_audio_file(self):
20
+ waveform = readAudioFile(self.stereo_file)
21
+ self.assertIsInstance(waveform, numpy.ndarray)
22
+ self.assertEqual(waveform.ndim, 2) # Stereo should have 2 dimensions
23
+ self.assertEqual(waveform.shape[0], 2) # First dimension should be 2 for stereo
24
+
25
+ class TestLoadWaveforms(unittest.TestCase):
26
+
27
+ def test_load_waveforms_mono(self):
28
+ """Test loading mono waveforms with different sample rates."""
29
+ path_filenames = [
30
+ pathlib.Path("unittests/dataSamples/testWooWooMono16kHz32integerClipping9secCopy1.wav"),
31
+ pathlib.Path("unittests/dataSamples/testWooWooMono16kHz32integerClipping9secCopy2.wav"),
32
+ pathlib.Path("unittests/dataSamples/testWooWooMono16kHz32integerClipping9secCopy3.wav"),
33
+ ]
34
+ array_waveforms = loadWaveforms(path_filenames, sampleRate=44100)
35
+ self.assertEqual(array_waveforms.shape, (2, 396900, 3))
36
+
37
+ def test_load_waveforms_stereo(self):
38
+ """Test loading stereo waveforms with different sample rates."""
39
+ path_filenames = [
40
+ pathlib.Path("unittests/dataSamples/testSine2ch5secCopy1.wav"),
41
+ pathlib.Path("unittests/dataSamples/testSine2ch5secCopy2.wav"),
42
+ pathlib.Path("unittests/dataSamples/testSine2ch5secCopy3.wav"),
43
+ pathlib.Path("unittests/dataSamples/testSine2ch5secCopy4.wav"),
44
+ ]
45
+ array_waveforms = loadWaveforms(path_filenames, sampleRate=44100)
46
+ self.assertEqual(array_waveforms.shape, (2, 220500, 4))
47
+
48
+ def test_load_waveforms_mixed_channels(self):
49
+ """Test loading a mix of mono and stereo waveforms."""
50
+ path_filenames = [
51
+ pathlib.Path("unittests/dataSamples/testWooWooMono16kHz32integerClipping9sec.wav"),
52
+ pathlib.Path("unittests/dataSamples/testSine2ch5sec.wav")
53
+ ]
54
+ array_waveforms = loadWaveforms(path_filenames, sampleRate=44100)
55
+ self.assertEqual(array_waveforms.shape, (2, 396900, 2))
56
+
57
+
58
+ if __name__ == "__main__":
59
+ unittest.main()
@@ -0,0 +1,59 @@
1
+ from pathlib import Path
2
+ from unittest.mock import patch
3
+ from Z0Z_tools import pipAnything
4
+ import tempfile
5
+ import unittest
6
+
7
+ class TestPipAnything(unittest.TestCase):
8
+
9
+ def test_makeListRequirementsFromRequirementsFile(self):
10
+ """
11
+ Test the makeListRequirementsFromRequirementsFile function.
12
+ """
13
+ with tempfile.TemporaryDirectory() as tempdir:
14
+ # Create a temporary requirements file
15
+ requirements_file = Path(tempdir) / 'requirements.txt'
16
+ requirements_content = """
17
+ # This is a comment
18
+ package-A==1.2.3
19
+ package-B>=4.5.6,<=7.8.9
20
+ package_C
21
+ # Another comment
22
+ analyzeAudio@git+https://github.com/hunterhogan/analyzeAudio.git
23
+ """
24
+ requirements_file.write_text(requirements_content)
25
+
26
+ # Test with a single file
27
+ requirements = pipAnything.makeListRequirementsFromRequirementsFile(requirements_file)
28
+ self.assertEqual(len(requirements), 4)
29
+ self.assertIn('package-A==1.2.3', requirements)
30
+ self.assertIn('package-B>=4.5.6,<=7.8.9', requirements)
31
+ self.assertIn('package_C', requirements)
32
+ self.assertIn('analyzeAudio@git+https://github.com/hunterhogan/analyzeAudio.git', requirements)
33
+
34
+ # Test with multiple files
35
+ requirements2 = pipAnything.makeListRequirementsFromRequirementsFile(requirements_file, requirements_file)
36
+ self.assertEqual(len(requirements2), 4) # Should still be 4, duplicates removed
37
+
38
+ # Test with non-existent file
39
+ nonexistent_file = Path(tempdir) / 'nonexistent.txt'
40
+ requirements3 = pipAnything.makeListRequirementsFromRequirementsFile(nonexistent_file)
41
+ self.assertEqual(len(requirements3), 0) # Should be empty
42
+
43
+ def test_make_setupDOTpy(self):
44
+ """
45
+ Test the make_setupDOTpy function.
46
+ """
47
+ relative_path_package = 'my_package'
48
+ list_requirements = ['numpy', 'pandas']
49
+ setup_content = pipAnything.make_setupDOTpy(relative_path_package, list_requirements)
50
+
51
+ # Check if the generated content contains expected elements
52
+ self.assertIn(f"name='{Path(relative_path_package).name}'", setup_content)
53
+ self.assertIn(f"packages=find_packages(where=r'{relative_path_package}')", setup_content)
54
+ self.assertIn(f"package_dir={{'': r'{relative_path_package}'}}", setup_content)
55
+ self.assertIn(f"install_requires={list_requirements},", setup_content)
56
+ self.assertIn("include_package_data=True", setup_content)
57
+
58
+ if __name__ == '__main__':
59
+ unittest.main()