PermissionError [Errno 13] Permission denied Python 2023

To whom it may concern,
Please read what I have to say before giving the usual response to this question. I have asked on multiple Discords after googling for Hours. I am to the point that i am writing on a Python forum to figure out what the issue could actually be. The screen shots linked will show that not only am I Admin on my PC, I also have enabled “Full Control” on the hard drive that the files are in. I have enabled every permission known to me. The files i am trying to read from the drive are indeed there, and the file location indeed does exist. I have no other editor open with those files, no excel, or Tiled program open. I have even ran Pycharm as Admin and get the same error. I have even gone as far as trying to open the files from my D: drive instead of my G: drive. I get the same error. All i am trying to accomplish is to open a “.tmx” from an export from Tiled to use what I made as a map in a pygame. I can send any and all Code relating to this in case my coding is the issue.

I also restarted the Computer multiple times in case the files did not close properly in Tiled.

As a new user, I can only upload one screenshot, I have several I need to share, so i am sharing the one that shows i am indeed an Admin so that can be cleared up that I have significant permissions

I appreciate you (anyone) taking the time to help me with this, especially near the holidays

If “the usual response” is “please post your code”, then I have read what you had to say and it’s still appropriate. Don’t post screenshots of code.

What is the appropriate way to post my code?

  # This is my main.py 
from tiles import *
from settings import *

from spritesheet import *

pygame.init()
DISPLAY_W, DISPLAY_H = 480, 270
canvas = pygame.Surface((DISPLAY_W, DISPLAY_H))
window = pygame.display.set_mode(((DISPLAY_W, DISPLAY_H)))
running = True
clock = pygame.time.Clock()





def __init__(self):
  self.Map_img = self.map.make_map()
  self.map_rect = self.Map_img.get_rect()
  self.Map_img = pygame.transform.scale(self.Map_img, (TILESIZE, TILESIZE))



while running:
  clock.tick(60)
  for event in pygame.event.get():
      if event.type == pygame.QUIT:
          running = False
      if event.type == pygame.KEYDOWN:
          pass

      canvas.fill((0, 180, 240))  # Fills the entire screen with light blue

      # canvas.blit(player_img, player_rect)
      window.blit(canvas, (0, 0))
      pygame.display.update()


  ```
   # This is my tile.py 
import pygame
import csv
import os
from pytmx.util_pygame import load_pygame

import settings

tmx_data = load_pygame("G:/Tiled/Game Python Files/Adjusted TileSet for MapEditor/Maps/Kanto Tiled Map Files")

#txtdata = load_pygame('G:/Tiled/Game Python Files/Adjusted TileSet for MapEditor/Text')

class Map:
   def __init__(self, filename):
       self.data = []
       self.tilewidth = len(self.data[0])
       self.tileheight = len(self.data)
       self.width = self.tilewidth * settings.TILESIZE
       self.height = self.tileheight * settings.TILESIZE


class Tile(pygame.sprite.Sprite):
   def __init__(self, pos, surface):
       super().__init__()
       self.image = surface
       self.rect = self.image.get_rect(topleft=pos)


for layer in tmx_data.visible_layers:

   if hasattr(layer, 'data'):
       for x, y, surface in layer.tiles():
           pos = (x * 16, y * 16)
           Tile(pos=pos, surface=surface)


class TiledMap:
   def __init__(self, filename):
       tm = pytmx.load_pygame(filename, pixelalpha=True)
       self.width = tm.width * tm.tilewidth
       self.height = tm.height * tm.tileheight
       self.tmxdata = tm

   def render(self, surface):
       ti = self.tmxdata.get_tile_image_by_gid
       for layer in self.tmxdata.visible_layers:
           if isinstance(layer, pytmx.TiledTileLayer):
               for x, y, gid, in layer:
                   tile = ti(gid)
                   if tile:
                       surface.blit(tile, (x * self.tmxdata.tilewidth,
                                           y * self.tmxdata.tileheight))

   def make_map(self):
       temp_surface = pygame.Surface((self.width, self.height))
       self.render(temp_surface)
       return temp_surface


class Camera:
   def __init__(self, width, height):
       self.camera = pygame.Rect(0, 0, width, height)
       self.width = width
       self.height = height

   def apply(self, entity):
       return entity.rect.move(self.camera.topleft)

   def apply_rect(self, rect):
       return rect.move(self.camera.topleft)

   def update(self, target):
       x = -target.rect.centerx + int(settings.WIDTH / 2)
       y = -target.rect.centery + int(settings.HEIGHT / 2)

       # limit scrolling to map size
       x = min(0, x)  # left
       y = min(0, y)  # top
       x = max(-(self.width - settings.WIDTH), x)  # right
       y = max(-(self.height - settings.HEIGHT), y)  # bottom
       self.camera = pygame.Rect(x, y, self.width, self.height)

   ```
    # This is my spritesheet.py   
import pygame
import json


class Spritesheet:
    def __init__(self, filename):
        self.filename = filename
        self.sprite_sheet = pygame.image.load(filename).convert()
        self.data = self.filename.replace('png', 'json', 'tmx', 'txt')
        with open(self.data, 'r', encoding='utf-8') as f:
            self.data = json.load(f)
        f.close()

    def get_sprite(self, x, y, w, h):
        sprite = pygame.Surface((w, h))
        sprite.set_colorkey((0, 0, 0))
        sprite.blit(self.sprite_sheet, (0, 0), (x, y, w, h))
        return sprite

    def parse_sprite(self, name):
        sprite = self.data['frames'][name]['frame']
        x, y, w, h = sprite["x"], sprite["y"], sprite["w"], sprite["h"]
        image = self.get_sprite(x, y, w, h)
        return image

    ```
    # This is my settings.py 
 import pygame
from spritesheet import *
vec = pygame.math.Vector2

WIDTH = 341
HEIGHT = 357

TILESIZE = 16
Map_IMG = '../Holder/Adjusted_Map_scale.png'

According to the documentation, the argument should be the path of a TMX file, but it looks like you passed the path of a directory.

On Windows, attempting to open a directory as if it’s a regular file fails with ERROR_ACCESS_DENIED, which the C runtime translates to EACCES (13). In turn, the Python runtime raises PermissionError. In this case, the permission error has nothing to do with file security.

Hi Brett, and welcome. Happy new year!

It looks like Eryk Sun has probably identified the cause of your error. Please let us know if that fixes it.

But for the future, please don’t dump dozens or hundreds of lines of code into our laps. We’re volunteers, not paid to analyse your code, and the more code you dump on us, the fewer volunteers you will get.

The best way to ask for help is to spend some time to produce a minimal reproducible example.

In your case, the minimal example would probably be something like:

from pytmx.util_pygame import load_pygame
tmx_data = load_pygame("G:/Tiled/Game Python Files/Adjusted TileSet for MapEditor/Maps/Kanto Tiled Map Files")

although as a beginner, you would be doing pretty well to get it down that far! But every bit helps: every additional 10 lines of code probably halves the number of people willing to read it. (Yes, we’re lazy. If you paid us, you could fire us, but you don’t so you can’t :slight_smile:

You can read more advice here.

Ideally, you should be aiming for maybe ten or twenty lines of code that we can run that demonstrates the problem.

@eryksun do you think the error message for EACCES (13) / PermissionError could be improved? Is it worth raising a ticket for it?

2 Likes

On Linux, open(".") raises IsADirectoryError, which is a subclass of OSError. Can someone with a Windows computer quickly check what happens there? If it is indeed PermissionError, then this is a Python-wide thing, but if it’s IsADirectoryError, this is actually a pygame issue and not a Python one.

>>> open('.')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
PermissionError: [Errno 13] Permission denied: '.'

Python open() calls WinAPI CreateFileW() without using the flag that enables opening directories (i.e. FILE_FLAG_BACKUP_SEMANTICS). In turn, CreateFileW() calls the NT system function NtCreateFile() with the option FILE_NON_DIRECTORY_FILE, which requires opening a regular file. In this case, if the opened path is a directory, the system call fails with the status code STATUS_FILE_IS_A_DIRECTORY. The CreateFileW() call maps this status code to the Windows error code ERROR_ACCESS_DENIED, which the C runtime maps to EACCES, and Python raises PermissionError.

One step that we could easily take in io.FileIO is to use the _doserrno value to get the underlying Windows error code when C _wopen() fails. This is sometimes helpful because commonly several Windows error codes are mapped to the same C errno value. (Unfortunately, it wouldn’t help in this case.) Note that, unlike open(), most of the functions in the os module report a winerror value in the exception because the Windows API is consumed directly. I don’t know why Python has never used the CRT’s _doserrno value. It isn’t standard C, but it dates back to a least the 1990s in the earliest versions of the CRT on NT systems, and it was always documented.

It’s also possible to get the original NT status code, but we’re on much more dubious footing in this case. The function to get the last NT status, RtlGetLastNtStatus(), is undocumented (but stable back to the 1990s). Moreover, the Windows API is free to set a last error that’s unrelated to the last NT status code. There’s no software contract regarding how the Windows API consumes the NT API. That said, it would help in this case, for whatever it’s worth.

For example:

import os
import errno
import ctypes

RtlGetLastNtStatus = ctypes.WinDLL('ntdll').RtlGetLastNtStatus
STATUS_FILE_IS_A_DIRECTORY = ctypes.c_long(0xC000_00BA).value
ERROR_ACCESS_DENIED = 5

# BUGBUG: In debug builds, this must use the debug CRT, "ucrtbased".
_doserrno = ctypes.CDLL('ucrtbase').__doserrno
_doserrno.restype = ctypes.POINTER(ctypes.c_ulong)

def opener(name, flags):
    try:
        return os.open(name, flags)
    except OSError as e:
        ntstatus = RtlGetLastNtStatus()
        winerror = _doserrno()[0]
        if (e.errno == errno.EACCES and winerror == ERROR_ACCESS_DENIED and
              ntstatus == STATUS_FILE_IS_A_DIRECTORY):
            e = IsADirectoryError(errno.EISDIR, os.strerror(errno.EISDIR),
                    e.filename, winerror)
            raise e from None
        raise
>>> open('.', opener=opener)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 24, in opener
IsADirectoryError: [WinError 5] Is a directory: '.'
2 Likes

PermissionError: [Errno 13] Permission denied: '.'
I have gotten this and been mystified before. If I get it in the future, I will look at the path more carefully.

Good to get that confirmed. Ugh, it’s a mess.

Worst case, would it be possible to do it as part of the exception-printed-to-console checks? Same place as going “hey, that’s a NameError, but maybe you meant this”, so it’s only costly when it actually ends the process. It’s not going to be perfect, as it would involve statting the file after the exception has gone through, but for common cases it would be easier to understand.

Actually, it occurs to me that there’s a simpler way to handle this. We can use the CRT’s undocumented flag[1] _O_OBTAIN_DIR (0x2000) to get backup semantics in the _wopen() call. Because POSIX open() allows opening a directory, io.FileIO already has to manually raise IsADirectoryError on POSIX systems, so we get that for ‘free’. For example:

import os

_O_OBTAIN_DIR = 0x2000

def opener(name, flags):
    return os.open(name, flags | _O_OBTAIN_DIR)
>>> open('.', opener=opener)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IsADirectoryError: [Errno 21] Is a directory: '.'

  1. Microsoft publishes the source code of the CRT, and the flag is in the public headers, so we’re not talking about an internal, private feature that we’ve reverse engineered. ↩︎

1 Like

Improving this error message would help a lot of people. It’s a common error and it’s always quite confusing / misleading.

2 Likes
```python
# FileNotFoundError: No such file or directory: 'G:/Tiled/Game Python Files/Adjusted 
#TileSet for MapEditor/Maps/Kanto Tiled Map Files\../Kanto Tiled Map 
#Files\../Map/Adjusted_Map_scale.png'.
#For some reason it can't find a png but i am specifying a .tmx
tmx_data = load_pygame("G:/Tiled/Game Python Files/Adjusted TileSet for 
MapEditor/Maps/Kanto Tiled Map Files/Kanto_alpha.tmx")
```

I was really excited that the error had a simple solution, though adding the .tmx to the path gives me a similar error except it is looking for a .png related to the project ( a png that made a .tsx tile set)

it would help me to understand the problem if i knew what was wrong
in this directory
‘G:/Tiled/Game Python Files/Adjusted TileSet for MapEditor/Maps/Kanto Tiled Map Files../Kanto Tiled Map Files../Adjusted TileSet for MapEditor/Towns or Cities/Pallet_town.png’
Why does it say —> /Kanto Tiled Map Files../Kanto Tiled Map Files../
More specifically, what does the ../ mean and why is it using the folder twice?
i’ve even tried stacking the folder to try to appease it with only getting more and more complex variations of the error

The double dot means to move up to the parent directory.

When Python goes to open the file, it has to walk through the list of folders:

'G:/Tiled/Game Python Files/Adjusted TileSet for MapEditor/Maps/Kanto Tiled Map Files\../Kanto Tiled Map Files\../Adjusted TileSet for MapEditor/Towns or Cities/Pallet_town.png'

so starting at G drive, it goes to Tiled then Game Python Files and so on, up to Maps then Kanto Tiled Map Files and then it hits the double dot .. which moves back up to the parent, namely Maps, and from there it tries to move to Kanto Tiled Map Files, then it his another double dot and moves back to Maps, and so on.

It’s a mess. Why is it written that way? I don’t know, you wrote it.

You should clean up the path, make sure it is correct, and that nothing is misspelled, and that the Pallet_town.png file actually exists where you are telling Python to look.

Also, you should only use forward slashes / for path separators, not the backslash, which can work in Windows but can also cause trouble. It’s often easier to just avoid backslashes by changing them into forward slashes.

# Sometimes this is problematic:
G:\Tiled\

# This is usually better:
G:/Tiled/

What does “stacking the folder” mean?

Making random changes to pathnames is unlikely to help. That’s like trying to fix a broken down car by randomly hitting parts of the engine with a big sledgehammer.

Apparently Brett called load_pygame("G:/Tiled/Game Python Files/Adjusted TileSet for MapEditor/Maps/Kanto Tiled Map Files/Kanto_alpha.tmx"). Then, for whatever reason, the pytmx library removed the base filename “Kanto_alpha.tmx” and tried to open "G:/Tiled/Game Python Files/Adjusted TileSet for MapEditor/Maps/Kanto Tiled Map Files\\../Map/Adjusted_Map_scale.png", which wasn’t found.