#StackBounty: #python #python-3.x #pdf #tiff Combine a bunch of PDFs converted from TIFF files as they're read in thru a loop

Bounty: 100

I’ve got a Python web scraper that crawls thru a bunch of TIFF pages online and converts each to PDF but I can’t figure out how to combine all the converted PDFs into one and write it to my computer.

import img2pdf, requests
outPDF = []

for pgNum in range(1,20):
    tiff = requests.get("http://url-to-tiff-file.com/page="+str(pgNum)).content
    pdf = img2pdf.convert(tiff)
    outPDF.append(pdf)

with open("file","wb") as f:
    f.write(''.join(outPDF))

I get the following error when I run it:

f.write(''.join(outPDF))
TypeError: sequence item 0: expected str instance, bytes found


Get this bounty!!!

#StackBounty: #python-3.x #django #csv django-import-export how to skip import some rows based on current user login?

Bounty: 50

Actually started using django-import-export latest version.
Wanted to know where exactly we can override to skip certain rows of the csv from being imported based on current user or the domains from a list of domains he can import data from the csv. How exactly to customize which of the methods to override and how?

In my ModelResource, I have created the list of domains for the current user, and which method of the import-export do I check this and skip the rows from being imported?

class MailboxResource(resources.ModelResource):
mdomain_list = []

def import_data(self, *args, **kwargs):
    # make changes to csv
    super(MailboxResource, self).before_import(*args, **kwargs)
    muser_id = kwargs['user'].id
    muser = kwargs['user']

    # import for all domains
    if muser.is_superuser:
        pass
    # import for domains belonging to the hierarchy
    elif muser is not None:
        exist = muser.groups.filter(name='customers').exists() 
        self.mdomain_list.append(Domain.objects.filter(
            customer__in=Customer.objects.filter(
                        email=muser)))

def skip_row(self, instance, original):
    mdomain = instance.email.partition('@')[2]
    #print(original, 'original',instance,'email', instance.email, self.mdomain_list)
    print(self.mdomain_list, 'llll', mdomain)
    if str(mdomain) in self.mdomain_list:
         print('will add', mdomain, instance.email)
         return False
    else:
         return True

Hence customer should be able to import data from the CSV only for domains that belong to him and skip all other rows from the CSV, which don’t exist in the list.
CSV:

id,name,email,domain,
1,ABC pvt.ltd,abc@zinn.com,zinn.com,
2,XTD,xtd@ggg.com,ggg.co.in,
3,RTG,tiger@goa.com,goa.com

If customer doesn’t own ggg.com domain, only 1st and 3rd row should get added to the table via import. How can this be achieved?

Using python 3.

Checked the document here: https://django-import-export.readthedocs.io/en/stable/api_resources.html#import_export.resources.Resource.skip_row but couldn’t make out much for my use-case.


Get this bounty!!!

#StackBounty: #python #python-3.x #django #apache #mod-wsgi Django/mod_wsgi/Apache – mod_wsgi is not using the Python version it was co…

Bounty: 100

I’m attempting to deploy a Django application with Apache2 and mod_wsgi on a Ubuntu 16.04.6 server, but I’m struggling with getting mod_wsgi to use the correct python version.

I installed mod_wsgi from source, and configured it to compile against the system python3, specifically python3.7.8

My Virtual environment for the Django app is also running python3.7.8.

My VirtualHost config file looks like this:

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName kumberas.com
        ServerAdmin webmaster@localhost.com

        WSGIScriptAlias / /home/dan/app/kumberas/kumberas/main/wsgi.py
        Alias /static/ /home/dan/app/kumberas/kumberas/static/

        <Directory /home/dan/app/kumberas/kumberas/static>
            Require all granted
        </Directory>

        <Directory /home/dan/app/kumberas/venv>
            Require all granted
        </Directory>

        <Directory /home/dan/app/kumberas/kumberas/main>
            <Files wsgi.py>
                Require all granted
            </Files>
        </Directory>

        <Location />
            AuthType Basic
            AuthName "Restricted Content"
            AuthUserFile /etc/apache2/.htpasswd
            Require user kr
            AuthBasicProvider file
        </Location>

        WSGIDaemonProcess kumberas 
            python-home=/home/dan/app/kumberas/venv 
            python-path=/home/dan/app/kumberas
        WSGIProcessGroup kumberas

    </VirtualHost>
</IfModule>

And when I try to access the site, I get a 500 Error and the following in my Apache error log.

[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603] mod_wsgi (pid=21635): Failed to exec Python script file '/home/dan/app/kumberas/kumberas/main/wsgi.py'.
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603] mod_wsgi (pid=21635): Exception occurred processing WSGI script '/home/dan/app/kumberas/kumberas/main/wsgi.py'.
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603] Traceback (most recent call last):
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603]   File "/home/dan/app/kumberas/kumberas/main/wsgi.py", line 12, in <module>
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603]     from django.core.wsgi import get_wsgi_application
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603]   File "/home/dan/app/kumberas/venv/lib/python3.7/site-packages/django/__init__.py", line 1, in <module>
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603]     from django.utils.version import get_version
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603]   File "/home/dan/app/kumberas/venv/lib/python3.7/site-packages/django/utils/version.py", line 1, in <module>
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603]     import datetime
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603]   File "/usr/lib/python3.7/datetime.py", line 8, in <module>
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603]     import math as _math
[wsgi:error] [pid 21635] [remote xx.xx.xx.xx:58603] ModuleNotFoundError: No module named 'math'

I did a bit of digging and found this wsgi.py file in the mod_wsgi documentation for checking the python version that mod_wsgi is using, and get the following output when I visit the site:

sys.version = '3.7.2 (default, Jan 23 2020, 09:44:10) n[GCC 5.4.0 20160609]'
sys.prefix = '/home/dan/app/kumberas/venv'

I assume the mismatching python version 3.7.8 != 3.7.2 is the issue here, but as far as I’m aware there isn’t a python3.7.2 installation on the server, and I’ve reinstalled mod_wsgi several times making certain that I configure it to use 3.7.8.

I’ve also confirmed that while in the virtual environment I’m, a) able to run the Django application with manage.py runserver, and b) can run get_wsgi_application() manually in the Django shell.

Does anyone have any knowledge on whether this version mismatch is the issue, and how it could be resolved?


Get this bounty!!!

#StackBounty: #python-3.x #pip How to determine where pip3 installs binaries/scripts for non-user installs?

Bounty: 150

I can determine where pip installs package binaries/scripts with pip3 install --user mypackage using:

$(python3 -m site --user-base)/bin

Is there a mechanism for determining where non-user binaries/scripts get installed (e.g. pip3 install mypackage) get installed?

Note that I’m only interested in where the binaries/scripts get installed and NOT where the library code gets installed.

Update: the objective is to ensure that that the PATH environment variable contains the folder where the binaries/scripts get installed as this has caused some issues in the past for me.


Get this bounty!!!

#StackBounty: #python-3.x #azure #azureservicebus #azure-servicebus-topics In the Azure functions Python SDK, how do I get the number o…

Bounty: 150

I’m using Python 3.8 with azure-mgmt-servicebus= v. 1.0.0. I would like to get the number of topics for a given namespace. I have tried the below …

credential = ServicePrincipalCredentials(self._client_id, self._client_secret, tenant=self._tenant)
        sb_client = ServiceBusManagementClient(credential, self._subscription)
         ...
        topics = sb_client.topics.list_by_namespace(
                resource_group_name=self._resource_group_name,
                namespace_name=namespace
            )
            num_topics = 0
            while topics.current_page:
                num_topics += topics.current_page.count
                topics.next
            logging.info("num topics: %s", num_topics)

My "num_topics" consistently comes back with zero, despite the fact I have verified that my connection is being made (I can create a topic with the same connection) and I can see many topics for the given information in the Azure portal. I’m thinking I’m not using the API properly but am unsure where things are falling apart. How do I get the number of topics for a given namespace?


Get this bounty!!!

#StackBounty: #python #python-3.x #exception #cpython Why does raising an exception invoke __subclasscheck__?

Bounty: 50

Consider the following example that uses __subclasscheck__ for a custom exception type:

class MyMeta(type):
    def __subclasscheck__(self, subclass):
        print(f'__subclasscheck__({self!r}, {subclass!r})')

class MyError(Exception, metaclass=MyMeta):
    pass

Now when raising an exception of this type, the __subclasscheck__ method gets invoked; i.e. raise MyError() results in:

__subclasscheck__(<class '__main__.MyError'>, <class '__main__.MyError'>)
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    raise MyError()
__main__.MyError

Here the first line of the output shows that __subclasscheck__ got invoked to check whether MyError is a subclass of itself, i.e. issubclass(MyError, MyError). I’d like to understand why that’s necessary and how it’s useful in general.


I’m using CPython 3.8.1 to reproduce this behavior. I also tried PyPy3 (3.6.9) and here __subclasscheck__ is not invoked.


Get this bounty!!!

#StackBounty: #python #python-3.x #websocket Handling more websocket connections

Bounty: 100

I have the following basic code, which connects to a websocket server and receives some data:

import websocket, json, time

def process_message(ws, msg):
    message = json.loads(msg)
    print(message)

def on_error(ws, error):
    print('Error', e)

def on_close(ws):
    print('Closing')

def on_open(ws):
    def run(*args):
        Subs = []
       
        tradeStr=  """{"method": "SUBSCRIBE", "params":%s, "id": 1}"""%(json.dumps(Subs))
        ws.send(tradeStr)

    thread.start_new_thread(run, ())

def Connect():
    websocket.enableTrace(False)
    ws = websocket.WebSocketApp("wss://myurl", on_message = process_message, on_error = on_error, on_close = on_close)
    ws.on_open = on_open
    ws.run_forever()

Connect()

Now, I would like to create more connections to different servers and receive data concurrently in the same script. I tried the following:

def run(url):

    def process_message(ws, msg):
        message = json.loads(msg)
        print(message)

    def on_error(ws, error):
        print('Error', e)

    def on_close(ws):
        print('Closing')

    def on_open(ws):
        def run(*args):
            Subs = []
           
            tradeStr=  """{"method": "SUBSCRIBE", "params":%s, "id": 1}"""%(json.dumps(Subs))
            ws.send(tradeStr)

        thread.start_new_thread(run, ())

    def Connect():
        websocket.enableTrace(False)
        ws = websocket.WebSocketApp(url, on_message = process_message, on_error = on_error, on_close = on_close)
        ws.on_open = on_open
        ws.run_forever()

    Connect()

threading.Thread(target=run, kwargs={'url': 'url1'}).start()
threading.Thread(target=run, kwargs={'url': 'url2'}).start()
threading.Thread(target=run, kwargs={'url': 'url3'}).start()

Now, this code works, but I’m connecting to different URLs and I’m streaming data from all of them, but it seemed to me an "hacky" solution. I also don’t know if what I’m doing could be bad practice or not. Each connection will send around 600/700 small JSON dictionaries, and I need to update every record to the db.

So my question is: is this implementation ok? Since it works with threads, can it create problems in the long run? Should I do another library such as Tornado?


Get this bounty!!!

#StackBounty: #python-3.x #flask Adding query parameter for every flask GET request

Bounty: 200

Trying to figure out the right mechanism to use here.

I want to modify the flask request coming in every time.

I think the request is immutable, so I am trying to figure out if this mechanism exists.

Basically, I want to append a string onto the end of the request coming in.

I can hook into the request and the right time in a before_request handler like this:

@app.before_app_request
def before_request_custom():
    # Get the request
    req = flask.request

    method = str(req.method)

    if method == "GET":
        # Do stuff here
        pass

But I am not sure what to actually do to add this in, and don’t see a way to accomplish it…I guess i could redirect, but that seems silly in this case. Any ideas?


Get this bounty!!!

#StackBounty: #python-3.x #django #django-models #ffmpeg #django-rest-framework Encoded Video's path gets changed in database after…

Bounty: 50

Hey guys the I have this code to transcode video and it works well without celery. With celery, the path of the file in the database shows a different path and the video cannot be played in the browser, but it saves the file in the correct location in the pc.

If I don’t use celery, then the file path in database is media/videos/videos/<filename>.mp4 and file also gets saved here. This way the template is able to play the video. But if i use celery, the output gets saved in media/videos/videos/<filename>.mp4 but the path in database will be media/<filename>.mp4 somehow and thus template can’t play the video.

Is it because my page gets updated before the task? and not getting saved properly?

views.py

def post(self, *args, **kwargs):
    form = VideoPostForm(self.request.POST or None, self.request.FILES or None)
    if form.is_valid():
        video = form.save(commit=False)
        video.user = self.request.user
        video.save()
        form.save_m2m()
        # task_video_encoding(video.id)
        task_video_encoding.delay(video.id)
        return redirect(reverse('videos:my_video_home'))
    else:
        raise ValidationError('Check all form fields.')

encoding.py

def encode_video(video_id):
    video = VideoPost.objects.get(id = video_id)
    input_file_path = video.temp_file.path
    # print(input_file_path)
    input_file_name = video.title
    #get the filename (without extension)
    filename = os.path.basename(input_file_path)
    # print(filename)
    # path to the new file, change it according to where you want to put it
    output_file_name = os.path.join('{}.mp4'.format(filename))
    # print(output_file_name)
    # output_file_path = os.path.join(settings.MEDIA_ROOT, output_file_name)
    output_file_path = os.path.join(settings.MEDIA_ROOT, 'videos', 'videos', output_file_name)
    # print(output_file_path)

    for i in range(1):
        subprocess.call([settings.VIDEO_ENCODING_FFMPEG_PATH, '-i', input_file_path, '-codec:v', 'libx264', '-crf', '-preset', 'medium',
                    '-b:v', '3000k', '-maxrate', '-bufsize', '6000k', '-vf', 'scale=-2:720',
                    '-codec:a', 'aac', '-b:a', '128k', '-strict', '-2', output_file_path])
    # Save the new file in the database
    video.file = output_file_name
    video.save(update_fields=['file'])
    print(video.file)
    video.temp_file.delete()

models

class VideoPost(models.Model):
    user                = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
    title               = models.TextField(max_length=1000)
    temp_file           = models.FileField(upload_to='videos/temp_videos/', validators=[validate_file_extension], null=True)
    file                = models.FileField(upload_to='videos/videos/', validators=[validate_file_extension], blank=True, max_length=255)
    post_date           = models.DateTimeField(auto_now_add=True, verbose_name="Date Posted")
    updated             = models.DateTimeField(auto_now_add=True, verbose_name="Date Updated")
    slug                = models.SlugField(blank=True, unique=True, max_length=255)

Can anyone help me how to change this code in a way to show the converted video properly in the template.


Get this bounty!!!

#StackBounty: #python #python-3.x #pygame Dungeon Ball, a Pygame

Bounty: 50

I just completed the first release for my first game on Python, called Dungeon Ball. I’m looking for people to test out the app and give me some feedback and constructive criticism. I’d like to use this project as a way to improve my programming skills and hopefully learn some efficient programming practices.

The game is called Dungeon Ball. It is pretty basic at the moment. It is pretty similar to games on breaking bricks with a ball and a racquet/paddle but I haven’t included the bricks just yet. Currently, the goal is to just keep the ball from falling using the paddle. By hitting the paddle you get points, which causes you to level up. The higher the level, the faster the paddle and ball move.

Main.py

import pygame
from pygame.locals import *
import numpy as np 
import math
from sys import exit
pygame.init()

from variables import *

def gameOver():
    pygame.mixer.music.stop()
    sounds['gameOver'].play()
    keyStatus = True
    blinkerCount = 0
    blinkerState = True
    blinkTime = 15
    while keyStatus:
        pygame.draw.rect(DISPLAYSURF, colours['grey'], dimensions['arena'])
        # pygame.draw.rect(DISPLAYSURF, colours['brown'], dimensions['arena'], borderWidth)
        if blinkerState:
            textSurfaceObj = fonts['largeFont'].render('GAME OVER!', True, colours['red'])
            textRectObj = textSurfaceObj.get_rect()
            textRectObj.center = (boxSize[0]/2, boxSize[1]/2)
            DISPLAYSURF.blit(textSurfaceObj, textRectObj)

        scoreSurface = fonts['midFont'].render('Score : {}'.format(gameStatus['points']), True, colours['white'])
        scoreSurfaceRect = scoreSurface.get_rect()
        scoreSurfaceRect.center = (boxSize[0]/2, boxSize[1]/2 + 50)
        DISPLAYSURF.blit(scoreSurface, scoreSurfaceRect)

        blinkerCount += 1

        if blinkerCount % blinkTime == 0:
            blinkerCount = 0
            blinkerState = not blinkerState

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    sounds['gameOver'].stop()
                    keyStatus = False
                elif event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    exit()

        pygame.display.update()
        fpsClock.tick(FPS)

        if keyStatus == False:
            break

    main()

def renderFunction():
    global gameStatus
    pygame.draw.rect(DISPLAYSURF, colours['black'], dimensions['arena'])
    pygame.draw.rect(DISPLAYSURF, colours['brown'], dimensions['arena'], borderWidth)
    pygame.draw.rect(DISPLAYSURF, colours['red'], dimensions['paddle'])
    pygame.draw.circle(DISPLAYSURF, colours['blue'], (ball['position']['x'], ball['position']['y']), ball['rad'] , 0)
    pointSurface = fonts['tinyFont'].render('Points : ' + str(gameStatus['points']), True, colours['white'])
    pointSurfaceRect = pointSurface.get_rect()
    pointSurfaceRect.center = (40, boxSize[1]-10)
    DISPLAYSURF.blit(pointSurface, pointSurfaceRect)

    levelSurface = fonts['tinyFont'].render('Level : ' + str(gameStatus['level']), True, colours['white'])
    levelSurfaceRect = levelSurface.get_rect()
    levelSurfaceRect.center = (boxSize[0]-40, boxSize[1]-10)
    DISPLAYSURF.blit(levelSurface, levelSurfaceRect)

def introScreen():
    keyStatus = True
    blinkerCount = 0
    blinkerState = True
    blinkTime = 15
    pygame.mixer.music.load('audio/startScreenMusic.wav')
    pygame.mixer.music.play(-1, 0.0)
    while keyStatus:
        pygame.draw.rect(DISPLAYSURF, colours['grey'], dimensions['arena'])
        # pygame.draw.rect(DISPLAYSURF, colours['brown'], dimensions['arena'], borderWidth)
        textSurfaceObj = fonts['largeFont'].render(gameStatus['name'], True, colours['gold'])
        textRectObj = textSurfaceObj.get_rect()
        textRectObj.center = (boxSize[0]/2, boxSize[1]/2)
        DISPLAYSURF.blit(textSurfaceObj, textRectObj)

        if blinkerState:
            spaceSurfaceObj = fonts['midFont'].render('Press Enter to Continue', True, colours['white'])
            spaceRectObj = spaceSurfaceObj.get_rect()
            spaceRectObj.center = (boxSize[0]/2, boxSize[1]/2+50)
            DISPLAYSURF.blit(spaceSurfaceObj, spaceRectObj)

        versionSurface = fonts['tinyFont'].render(gameStatus['version'], True, colours['white'])
        versionSurfaceRect = versionSurface.get_rect()
        versionSurfaceRect.center = (boxSize[0]-20, boxSize[1]-10)
        DISPLAYSURF.blit(versionSurface, versionSurfaceRect)
        blinkerCount += 1

        if blinkerCount % blinkTime == 0:
            blinkerCount = 0
            blinkerState = not blinkerState

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    keyStatus = False
                elif event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    exit()
        pygame.display.update()
        fpsClock.tick(FPS)

    keyStatus=True
    pygame.mixer.music.stop()       

def eventHandler():
    global dimensions
    keys=pygame.key.get_pressed()
    if keys[K_LEFT] and not (dimensions['paddle'].left <= (dimensions['arena'].left+borderWidth)):
        direction = -1*paddle['speed']
        # print('hi left')
        paddle['position']['x'] += direction
    elif keys[K_RIGHT] and not (dimensions['paddle'].right >= (dimensions['arena'].right-borderWidth)):
        direction = paddle['speed']
        # print('hi right')
        paddle['position']['x'] += direction
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            exit()

    dimensions['paddle'] = pygame.Rect(paddle['position']['x'], paddle['position']['y'], paddle['length'], 10)

def ballEngine():
    global gameStatus
    if (ball['position']['x'] <= (dimensions['arena'].left+borderWidth+ball['rad'])):
        # print('LeftSideBounce')
        ball['direction'] = 180 - ball['direction'] + np.random.randint(-1*gameStatus['random'],gameStatus['random'])
        sounds['wallHit'].play()

    elif (ball['position']['x'] >= (dimensions['arena'].right-borderWidth-ball['rad'])):
        # print('RightSideBounce')
        ball['direction'] = 180 - ball['direction'] + np.random.randint(-1*gameStatus['random'],gameStatus['random'])
        sounds['wallHit'].play()

    elif ball['position']['y'] <= (dimensions['arena'].top+borderWidth+ball['rad']):
        # print('TopBounce')
        ball['direction'] = 360 - ball['direction'] + np.random.randint(-1*gameStatus['random'],gameStatus['random'])

        if ball['direction'] >= 250 and ball['direction'] <= 290:
            ball['direction'] += np.random.randint(-2*gameStatus['random'],2*gameStatus['random'])

        sounds['wallHit'].play()
    elif ball['position']['y'] >= (dimensions['arena'].bottom - borderWidth - ball['rad']):
        # print('BottomBounce')
        # ball['speed'] = 0
        # gameStatus = True
        gameOver()
    # print(ball['direction'])
    if (ball['position']['y'] >= (paddle['position']['y']-ball['rad']) and ball['position']['y'] <= paddle['position']['y']+dimensions['paddle'].height+ball['rad']) and ball['position']['x'] >= dimensions['paddle'].left and ball['position']['x'] <= dimensions['paddle'].right:
        # print('Paddle hit')
        ball['direction'] = 360 - ball['direction'] + np.random.randint(-1*gameStatus['random'],gameStatus['random'])
        gameStatus['points'] = gameStatus['points'] + 1

        sounds['paddleHit'].play()
        print(ball['position'], paddle['position'], ball['direction'])

        gameStatus['paddleHitsPerLevel'] += 1

        if ball['position']['y'] >= dimensions['paddle'].top and ball['position']['y'] <= dimensions['paddle'].bottom:
            ball['position']['y'] = dimensions['paddle'].top - ball['rad']

        if gameStatus['paddleHitsPerLevel'] == (gameStatus['level']*5) and not gameStatus['points']  == 0:
            ball['speed'] += 2
            gameStatus['level'] += 1
            gameStatus['random'] += 2
            gameStatus['paddleHitsPerLevel'] = 0
            sounds['levelUp'].play()

        if gameStatus['points'] % 10 == 0 and not gameStatus['points']  == 0:
            paddle['speed'] += 1

    if (ball['direction']>360 or ball['direction'] < 0):
        ball['direction'] %= 360

    if ball['direction'] % 90 >= 85 and ball['direction'] % 90 <=89 or ball['direction'] % 90 >= 0 and ball['direction'] % 90 <= 5:
        ball['direction'] += np.random.randint(-2*gameStatus['random'],2*gameStatus['random'])


    if ball['position']['y'] < borderWidth+ball['rad']:
        ball['position']['y'] = borderWidth+ball['rad']
    elif ball['position']['x'] < borderWidth+ball['rad']:
        ball['position']['x'] = borderWidth+ball['rad']
    elif ball['position']['x'] > dimensions['arena'].right-borderWidth-ball['rad']:
        ball['position']['x'] = dimensions['arena'].right-borderWidth-ball['rad']

    ball['position']['x'] += int(ball['speed']*math.cos(ball['direction']*math.pi/180))
    ball['position']['y'] += int(ball['speed']*math.sin(ball['direction']*math.pi/180))

def init():
    global ball, paddle, gameStatus
    ball['position']['x']=boxSize[0]/2
    ball['position']['y']=int(boxSize[1]/3)
    ball['direction']=np.random.randint(295, 325)
    ball['speed']=5
    ball['rad']=5

    paddle['position']['x']=boxSize[0]/2
    paddle['position']['y']=boxSize[1]-50
    paddle['length']=100
    paddle['speed']=5

    gameStatus['points']=0
    gameStatus['level']=1
    gameStatus['random']=5

def main():
    introScreen()
    init()
    pygame.mixer.music.load('audio/gamePlayMusic.wav')
    pygame.mixer.music.play(-1, 0.0)

    while True:
        eventHandler()
        ballEngine()
        renderFunction()
        pygame.display.update()
        fpsClock.tick(FPS)

if __name__ == '__main__':
    fpsClock = pygame.time.Clock()
    DISPLAYSURF = pygame.display.set_mode(boxSize, 0, 32)
    pygame.display.set_caption(gameStatus['name'])
    main()

Variables.py

import numpy as np
import pygame
pygame.init()
from pygame.locals import *
import os

FPS = 30
borderWidth = 5

boxSize = (700, 400)

colours = {'black':(0, 0, 0),
           'red': (255, 0, 0),
           'blue':(0, 0, 255),
           'brown':(210, 105, 30),
           'green':(0, 255, 0),
           'white':(255, 255, 255),
           'gold':(255, 215, 0),
           'silver':(192, 192, 192),
           'grey':(128, 128, 128)}

ball = {'position':{'x':boxSize[0]/2, 'y':boxSize[1]/3}, 'direction':np.random.randint(295, 325), 'speed':5, 'rad':5}

paddle = {'position':{'x':boxSize[0]/2, 'y':boxSize[1]-50}, 'length':100, 'speed':5}

dimensions = {
              'arena': pygame.Rect(0, 0, boxSize[0], boxSize[1]+10), 
              'paddle': pygame.Rect(paddle['position']['x'], paddle['position']['y'], paddle['length'], 10)
             }

gameStatus = {'points': 0, 'level': 1, 'random': 5, 'paddleHitsPerLevel':0, 'name': 'Dungeon Ball', 'version': 'v1.0'}


fonts = {
         'largeFont':pygame.font.Font(os.path.join(os.getcwd(),'fonts','Ancient_Modern_Tales_Regular.ttf'), 64),
         'midFont':pygame.font.Font(os.path.join(os.getcwd(),'fonts', 'Old_School_Adventures_Regular.ttf'), 12),
         'tinyFont': pygame.font.Font(os.path.join(os.getcwd(),'fonts', 'Old_School_Adventures_Regular.ttf'), 8)
        }

sounds = {
            'paddleHit': pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'paddle_hit.wav')), 
            'wallHit': pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'wall_hit.wav')), 
            'gameOver':pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'game_over.wav')),
            'levelUp': pygame.mixer.Sound(os.path.join(os.getcwd(), 'audio', 'level_up.wav'))
        }

Currently, the release is only for Linux and Windows. Mac users could try and build the environment and run the program directly. First step, you need to download your OS specific release and unzip it. Enter the extracted directory. Windows users just double click to run. Linux users need to open the directory in terminal and run ./main.


Get this bounty!!!