Tempfile path returning int python3 - python

I would like to know if there is a way to find the path of a temporary file without it returning an int (15 in my case). I would like to return a string (or an object in which I can then turn into one, please detail how) path is the path to the temp file (and the name of it). Example: /Users/FooBar/Python3.6/Modules/TempFile/Opus/THE_TEMP_FILE or something like that. I have already written a small .wav file to it and would like to get the path to get the playing time/duration of it using os .stat(). I want to use a temporary file because I am lazy and I do not want to do a lot of 'special' code for the four different operating systems I am trying to this program on. Here is my code:
import pygame, time, os, tempfile
import urllib.request as ur
pygame.init() # Initialize the pygame
DISPLAYSURF = pygame.display.set_mode((1, 1)) # Sets display. Needed to play sound
sound = input('What sound should play: ') # Asks which sound
url = 'http://207.224.195.43:8000/' + sound # Gets server url
response = ur.urlopen(url) # Open url
data = response.read() # Create byte like object containing .wav code
f = tempfile.TemporaryFile() # Create TempFile
f.write(data) # Write .wav data gotten from server
f.seek(0) # Prepare to read it
soundObj = pygame.mixer.Sound(f.read()) # Load sound to be played
f.seek(0) # Prepare to read it
statbuf = os.stat(f.name) # Gets stats from TempFile. Returns int, I want to fix that
mbytes = statbuf.st_size / 1024 # Gets 'not real' sound duration
soundObj.play() # Plays sounds
time.sleep(mbytes / 200) # Gets 'real' sound duration and waits
soundObj.stop() # Stops sounds once done
Let me know (comment) if you have any suggestions. I have looked at a few sites, one of which was on stack-overflow, one that you could mistake to be a duplicate of this question. It was about Django which as I understand is entirely different then python. Thanks for possibly answering this question. Remember, I am not looking for a confirmation on this is an issue, I already know that. Please give me a possible answer to the question as soon as you can.
Thanks!
-User 9311010

The whole point of tempfile.TemporaryFile is that there is no name for the file, if at all possible:
… Under Unix, the directory entry for the file is either not created at all or is removed immediately after the file is created. Other platforms do not support this; your code should not rely on a temporary file created using this function having or not having a visible name in the file system.
If you want a temporary file with an accessible filename, use NamedTemporaryFile:
This function operates exactly as TemporaryFile() does, except that the file is guaranteed to have a visible name in the file system… That name can be retrieved from the name attribute of the returned file-like object.
However, I don't think you need a filename in the first place. Do you only want one so you have something to pass to stat? In Python 3.3+, you can pass a file object (like f) to stat instead of its name. In older versions, you can use fstat with the file's descriptor (fileno()).

Related

Is there any feasible solution to read WOT battle results .dat files?

I am new here to try to solve one of my interesting questions in World of Tanks. I heard that every battle data is reserved in the client's disk in the Wargaming.net folder because I want to make a batch of data analysis for our clan's battle performances.
image
It is said that these .dat files are a kind of json files, so I tried to use a couple of lines of Python code to read but failed.
import json
f = open('ex.dat', 'r', encoding='unicode_escape')
content = f.read()
a = json.loads(content)
print(type(a))
print(a)
f.close()
The code is very simple and obviously fails to make it. Well, could anyone tell me the truth about that?
Added on Feb. 9th, 2022
After I tried another set of codes via Jupyter Notebook, it seems like something can be shown from the .dat files
import struct
import numpy as np
import matplotlib.pyplot as plt
import io
with open('C:/Users/xukun/Desktop/br/ex.dat', 'rb') as f:
fbuff = io.BufferedReader(f)
N = len(fbuff.read())
print('byte length: ', N)
with open('C:/Users/xukun/Desktop/br/ex.dat', 'rb') as f:
data =struct.unpack('b'*N, f.read(1*N))
The result is a set of tuple but I have no idea how to deal with it now.
Here's how you can parse some parts of it.
import pickle
import zlib
file = '4402905758116487.dat'
cache_file = open(file, 'rb') # This can be improved to not keep the file opened.
# Converting pickle items from python2 to python3 you need to use the "bytes" encoding or "latin1".
legacyBattleResultVersion, brAllDataRaw = pickle.load(cache_file, encoding='bytes', errors='ignore')
arenaUniqueID, brAccount, brVehicleRaw, brOtherDataRaw = brAllDataRaw
# The data stored inside the pickled file will be a compressed pickle again.
vehicle_data = pickle.loads(zlib.decompress(brVehicleRaw), encoding='latin1')
account_data = pickle.loads(zlib.decompress(brAccount), encoding='latin1')
brCommon, brPlayersInfo, brPlayersVehicle, brPlayersResult = pickle.loads(zlib.decompress(brOtherDataRaw), encoding='latin1')
# Lastly you can print all of these and see a lot of data inside.
The response contains a mixture of more binary files as well as some data captured from the replays.
This is not a complete solution but it's a decent start to parsing these files.
First you can look at the replay file itself in a text editor. But it won't show the code at the beginning of the file that has to be cleaned out. Then there is a ton of info that you have to read in and figure out but it is the stats for each player in the game. THEN it comes to the part that has to do with the actual replay. You don't need that stuff.
You can grab the player IDs and tank IDs from WoT developer area API if you want.
After loading the pickle files like gabzo mentioned, you will see that it is simply a list of values and without knowing what the value is referring to, its hard to make sense of it. The identifiers for the values can be extracted from your game installation:
import zipfile
WOT_PKG_PATH = "Your/Game/Path/res/packages/scripts.pkg"
BATTLE_RESULTS_PATH = "scripts/common/battle_results/"
archive = zipfile.ZipFile(WOT_PKG_PATH, 'r')
for file in archive.namelist():
if file.startswith(BATTLE_RESULTS_PATH):
archive.extract(file)
You can then decompile the python files(uncompyle6) and then go through the code to see the identifiers for the values.
One thing to note is that the list of values for the main pickle objects (like brAccount from gabzo's code) always has a checksum as the first value. You can use this to check whether you have the right order and the correct identifiers for the values. The way these checksums are generated can be seen in the decompiled python files.
I have been tackling this problem for some time (albeit in Rust): https://github.com/dacite/wot-battle-results-parser/tree/main/datfile_parser.

pydub AudioSegment.export is locking a file on smb share. Can't delete that file

I am running into an issue when trying to extract mono audio from a stereo file using pydub.
Here is the code:
import wave
import audioop
from pydub import AudioSegment
def cantDeleteLockedFile():
audiofile = "/Volumes/test/stereotest.wav"
audiostrip = AudioFileClip(audiofile)
if audiostrip.nchannels > 1:
with open(audiofile, "rb") as oaudiofile:
mono_audios = AudioSegment.from_file(oaudiofile, format="wav")
# List of AudioSegments, mono files, which can be accessed via [0] and [1]
mono_audios = mono_audios.split_to_mono()
audioChannelOne = str(audiofile.rsplit(".", 1)[0]) + "a.wav"
# This line is locking the stereo file
mono_left = mono_audios[0].export(audioChannelOne, format="wav")
# This extracts the mono left track from the stereo track
# On the same location a file will be created, in this example:
# "/Volumes/test/stereotesta.wav"
# This should unlock the file, but doesnt
mono_left.close()
# When trying to delete the file here, it will fail
# without exception raised
os.remove(audiofile)
if os.path.exists(audiofile):
return True
else:
return False
return False
After executing this code, which in my case is embedded into an API microservice system, that does not exit the code. Then the stereo audio file will be locked, for as long as that micro service is running. The file will not be deleted and function return value will be "False". If you later manually on the filesystem navigate to that file and try to delete it manually, it will also fail. It will first delete it, but then it will magically pop back up.
I am aware of this issue being discussed on other boards before. However the proposed solution does not work.
ref: https://github.com/jiaaro/pydub/issues/305
Either I am missing something completely. However, perhaps there is a workaround to forcibly unlock a file, so it can be deleted? I did not find a reference online.
Basically I know, that pydub is locking the resource, I can't get it to unlock the wav file behind the Audio Segment.
Happy to read your feedback and suggestions.
Thank you!
The Audiosegment used to check for stereo files also needs to be closed.
This was blocking the file on the storage side.
Adding a simple:
audiostrip.close()
solved the problem.

Need to connect to ftp through the ftputil module, open an existing file with records and add new records to the end of those records

I used the ftputil module for this, but ran into a problem that it doesn't support 'a'(append) appending to the file, and if you write via 'w' it overwrites the contents.
That's what I tried and I'm stuck there:
with ftputil.FTPHost(host, ftp_user, ftp_pass) as ftp_host:
with ftp_host.open("my_path_to_file_on_the_server", "a") as fobj:
cupone_wr = input('Enter coupons with a space: ')
cupone_wr = cupone_wr.split(' ')
for x in range(0, len(cupone_wr)):
cupone_str = '<p>Your coupon %s</p>\n' % cupone_wr[x]
data = fobj.write(cupone_str)
print(data)
The goal is to leave the old entries in the file and add fresh entries to the end of the file every time the script is called again.
Indeed, ftputil does not support appending. So either you will have to download complete file and reupload it with appended records. Or you will have to use another FTP library.
For example the built-in Python ftplib supports appending. On the other hand, it does not (at least not easily) support streaming. Instead, it's easier to construct the new records in-memory and upload/append them at once:
from ftplib import FTP
from io import BytesIO
flo = BytesIO()
cupone_wr = input('Enter coupons with a space: ')
cupone_wr = cupone_wr.split(' ')
for x in range(0, len(cupone_wr)):
cupone_str = '<p>Your coupon %s</p>\n' % cupone_wr[x]
flo.write(cupone_str)
ftp = FTP('ftp.example.com', 'username', 'password')
flo.seek(0)
ftp.storbinary('APPE my_path_to_file_on_the_server', flo)
ftputil author here :-)
Martin is correct in that there's no explicit append mode. That said, you can open file-like objects with a rest argument. In your case, rest would need to be the original length of the file you want to append to.
The documentation warns against using a rest argument that points after the file because I'm quite sure rest isn't expected to be used that way. However, if you use your program only against a specific server and can verify its behavior, it might be worthwhile to experiment with rest. I'd be interested whether it works for you.

RedVox Python SDK | Not Reading in .rdvxz Files

I'm attempting to read in a series of files for processing contained in a single directory using RedVox:
input_directory = "/home/ben/Documents/Data/F1D1/21" # file location
rdvx_data = DataWindow(input_dir=input_directory, apply_correction=False, debug=True) # using RedVox to read in the files
print(os.listdir(input_directory)) # verifying the files actually exist...
# returns "['file1.rdvxz', 'file2.rdvxz', file3.rdvxz', ...etc]", they exist
# write audio portion to file
rdvx_data.to_json_file(base_dir=output_rpd_directory,
file_name=output_filename)
# this never runs, because rdvx_data.stations = [] (verified through debugging)
for station in rdvx_data.stations:
# some code here
Enabling debugging through arguments as seen above does not provide an extra details. In fact, there is no error message whatsoever. It writes the JSON file and pickle to disk, but the JSON file is full of null values and the pickle object is just a shell, no contents. So the files definitely exist, os.listdir() sees them, but RedVox does not.
I assume this is some very silly error or lack of understanding on my part. Any help is greatly appreciated. I have not worked with RedVox previously, nor do I have much understanding of what these files contain other than some audio data and some other data. I've simply been tasked with opening them to work on a model to analyze the data within.
SOLVED: Not sure why the previous code doesn't work (it was handed to me), however, I worked around the DataWindow call and went straight to calling the "redvox.api900.reader" object:
from redvox.api900 import reader
dataset_dir = "/home/*****/Documents/Data/F1D1/21/"
rdvx_files = glob(dataset_dir+"*.rdvxz")
for file in rdvx_files:
wrapped_packet = reader.read_rdvxz_file(file)
From here I can view all of the sensor data within:
if wrapped_packet.has_microphone_sensor():
microphone_sensor = wrapped_packet.microphone_sensor()
print("sample_rate_hz", microphone_sensor.sample_rate_hz())
Hope this helps anyone else who's confused.

Saving a temporary file

I'm using xlwt in python to create a Excel spreadsheet. You could interchange this for almost anything else that generates a file; it's what I want to do with the file that's important.
from xlwt import *
w = Workbook()
#... do something
w.save('filename.xls')
I want to I have two use cases for the file: I stream it out to the user's browser or I attach it to an email. In both cases the file only needs to exist the duration of the web request that generates it.
What I'm getting at, the reason for starting this thread is saving to a real file on the filesystem has its own hurdles (stopping overwriting, cleaning up the file once done). Is there somewhere I could "save" it where it lives only in memory and only for the duration of the request?
cStringIO
(or mmap if it should be mutable)
Generalising the answer, as you suggested: If the "anything else that generates a file" won't accept a file-like object as well as a filepath, then you can reduce the hassle by using tempfile.NamedTemporaryFile

Categories

Resources