Python Forum
subprocess FileNotFoundError: [Errno 2] No such file or directory:
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
subprocess FileNotFoundError: [Errno 2] No such file or directory:
#1
I am trying to convert emojis to svg images, using Python I got from github here

I adapted the Python to fit my system and paths.

When subprocess runs the command that is built:

Quote:/usr/bin/inkscape --export-overwrite --actions="select-by-id:text-box; object-to-path; export-id:text-box; export-id:text-box; export-do; FileClose;" /home/peterr/PVE/emoji2svg2png/svg/Animals & Nature - 9728 (black sun with rays).svg

I get a FileNotFoundError:

Quote:Traceback (most recent call last):
File "/home/peterr/PVE/emoji2svg2png/export-all-emojiV2.py", line 109, in <module>
generate_symbols()
File "/home/peterr/PVE/emoji2svg2png/export-all-emojiV2.py", line 86, in generate_symbols
write_new_letter(glyph, hex_code, decimal, name, category)
File "/home/peterr/PVE/emoji2svg2png/export-all-emojiV2.py", line 51, in write_new_letter
convert_to_path(file_name)
File "/home/peterr/PVE/emoji2svg2png/export-all-emojiV2.py", line 67, in convert_to_path
subprocess.call(command)
File "/usr/lib/python3.12/subprocess.py", line 389, in call
with Popen(*popenargs, **kwargs) as p:
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/subprocess.py", line 1026, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/usr/lib/python3.12/subprocess.py", line 1955, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/inkscape --export-overwrite --actions="select-by-id:text-box; object-to-path; export-id:text-box; export-id:text-box; export-do; FileClose;" /home/peterr/PVE/emoji2svg2png/svg/Animals & Nature - 9728 (black sun with rays).svg'

The file: /home/peterr/PVE/emoji2svg2png/svg/Animals & Nature - 9728 (black sun with rays).svg is created, but it is empty!

I tried some simple inkscape commands in bash, which worked ok, so I don't think inkscape is the problem:

Quote:# works
/usr/bin/inkscape --export-type="png" greenArrow1.svg
# worked but empty file
inkscape --export-type="png" symbol-template.svg
# works
inkscape --export-type="png" greenArrow1.svg
# read svg export as pdf
cat greenArrow1.svg | inkscape --pipe --export-filename=greenArrow1.pdf

This is the code from github, adapted a little for my setup:

#! /usr/bin/python3
import os
import subprocess
from typing import List, TextIO

# Reads a font and generates an SVG file for every emoji
savepath = "/home/peterr/PVE/emoji2svg2png/svg/"

# UTF8 encoded table which all Unicode symbols
# Header: Symbol;Hex-Code;Name;Is-Emoji (0 | 1);Group
# Example: ๐Ÿ‘;1F44D;THUMBS UP SIGN;1;Body;
# Only symbols which are marked with Is-Emoji (1) are processed.
symbol_table = "/home/peterr/PVE/emoji2svg2png/symbol-table.csv"

# Simple SVG-Template with one centered symbol.
symbol_template = "/home/peterr/PVE/emoji2svg2png/symbol-template.svg"

# font name to replace Arial with.
font = "NotoColorEmoji"

# try with either path, still get FileNotFoundError
#inkscape_path = 'inkscape '
inkscape_path = '/usr/bin/inkscape'

action_object_to_path = ' --export-overwrite --actions="select-by-id:text-box; object-to-path; export-id:text-box; '
# export-id:text-box; is here a second time
action_export = 'export-id:text-box; export-do; FileClose;" '

# Set True to print all executed commands
#debug = False
debug = True

# Writes a unicode emoji as svg into the savepath
def write_new_letter(glyph, hex_code, decimal, name, category):
    # the actual text file name
    letter_template: TextIO = open(symbol_template, "r")

    template_letter = "A"
    file_name = savepath + category + " - " + str(decimal) + " (" + name.lower() + ").svg"
    #new_letter = open(file_name, "x", encoding='utf-8') # think "x" means exclusive, fails if exists
    new_letter = open(file_name, "w", encoding='utf-8')

    lines: list[str] = letter_template.readlines()

    export_data = []
    for line in lines:
        export_data += line \
            .replace(">" + template_letter + "<", ">" + glyph + "<") \
            .replace("Arial", font)

    new_letter.writelines(export_data)
    new_letter.close()
    convert_to_path(file_name)


##def convert_to_path(file_name):
##    input_file = '"' + file_name + '"'
##    command = inkscape_path + action_object_to_path + action_export + input_file
##    if debug:
##        print(command)
##    subprocess.call(command)
##    print("New symbol: " + input_file)

def convert_to_path(file_name):
    command = inkscape_path + action_object_to_path + action_export + file_name
    if debug:
        print(command)
    subprocess.call(command)
    print("New symbol: " +  file_name)


# Reads all Unicode-Emoji which are listed in the $symbol_table.
# Only symbols which are marked with Is-Emoji (1) are processed.
def generate_symbols():
    emoji_list = open(symbol_table, "r", encoding='utf-8')
    i = 0
    for line in emoji_list:
        i = i + 1
        values = line.split(",")
        glyph = values[0]
        hex_code = values[1]
        decimal = int(hex_code, 16)
        name = values[2]
        is_emoji = values[3] == "1"
        category = values[4].strip()
        if is_emoji:
            write_new_letter(glyph, hex_code, decimal, name, category)

##def generate_symbols():
##    with open(symbol_table) as infile:
##        emoji_list = infile.readlines()
##    i = 0
##    for line in emoji_list:
##        # there is a \n from the csv at the end of each line
##        line = line.strip()
##        i = i + 1
##        values = line.split(",")
##        glyph = values[0]
##        hex_code = values[1]
##        decimal = int(hex_code, 16)
##        name = values[2]
##        is_emoji = values[3] == "1" # True if values[3] == 1
##        category = values[4]
##        if is_emoji:
##            write_new_letter(glyph, hex_code, decimal, name, category)


if __name__ == '__main__':
    print("Exporting all emoji...")
    generate_symbols()
    print("Finished export")
subprocess doesn't process the command properly. It seems to think the whole command is a file name.

Any tips please? I have never used subprocess before.
Reply
#2
(Aug-03-2025, 12:45 AM)Pedroski55 Wrote: Any tips please? I have never used subprocess before.
There are basically two ways to call commands with subprocess:

With a list of strings
subprocess.call(["spam", "--eggs", "--ham='foo'"])
or with a single string and the option shell=True
subprocess.call("spam --eggs --ham='foo'", shell=True)
In the second form, a shell process is started and the command is parsed and called as a child process of this shell process. It is also less secure.

By default, I always choose the first form because there is no reason to start a shell process in addition to the new process.
buran likes this post
ยซ We can solve any problem by introducing an extra level of indirection ยป
Reply
#3
Thanks, that improved things somewhat: I made a csv file with only 4 emojis and relevant data.
I tried with shell=True

I get an output, but the output is BLACK. I was hoping for a copy of the emoji as .svg in COLOUR!

Quote:peterr@peterr-Modern-15-B7M:~/PVE/emoji2svg2png$ python3 export-all-emojiV2.py
Exporting all emoji...
/usr/bin/inkscape --export-overwrite --actions="select-by-id:text-box; object-to-path; export-id:text-box; export-id:text-box; export-do; FileClose" /home/peterr/PVE/emoji2svg2png/svg/Animals & Nature - 9728 (black sun with rays).svg
/bin/sh: 1: Syntax error: "(" unexpected
New symbol: /home/peterr/PVE/emoji2svg2png/svg/Animals & Nature - 9728 (black sun with rays).svg
/usr/bin/inkscape --export-overwrite --actions="select-by-id:text-box; object-to-path; export-id:text-box; export-id:text-box; export-do; FileClose" /home/peterr/PVE/emoji2svg2png/svg/Animals & Nature - 129370 (egg).svg
/bin/sh: 1: Syntax error: "(" unexpected
New symbol: /home/peterr/PVE/emoji2svg2png/svg/Animals & Nature - 129370 (egg).svg
/usr/bin/inkscape --export-overwrite --actions="select-by-id:text-box; object-to-path; export-id:text-box; export-id:text-box; export-do; FileClose" /home/peterr/PVE/emoji2svg2png/svg/Drinks - 9749 (hot beverage).svg
/bin/sh: 1: Syntax error: "(" unexpected
New symbol: /home/peterr/PVE/emoji2svg2png/svg/Drinks - 9749 (hot beverage).svg
/usr/bin/inkscape --export-overwrite --actions="select-by-id:text-box; object-to-path; export-id:text-box; export-id:text-box; export-do; FileClose" /home/peterr/PVE/emoji2svg2png/svg/Body - 128513 (grinning face with smiling eyes).svg
/bin/sh: 1: Syntax error: "(" unexpected
New symbol: /home/peterr/PVE/emoji2svg2png/svg/Body - 128513 (grinning face with smiling eyes).svg
Finished export
peterr@peterr-Modern-15-B7M:~/PVE/emoji2svg2png$

Do you think I should split this into individual chunks, separated by commas?

/usr/bin/inkscape --export-overwrite --actions="select-by-id:text-box; object-to-path; export-id:text-box; export-id:text-box; export-do; FileClose" /home/peterr/PVE/emoji2svg2png/svg/Animals & Nature - 9728 (black sun with rays).svg
Reply
#4
(Aug-03-2025, 08:47 AM)Pedroski55 Wrote: Do you think I should split this into individual chunks, separated by commas?
No you have a shell parsing error because the file name contains white space. Use quotes around the file name
Output:
"/home/peterr/PVE/emoji2svg2png/svg/Animals & Nature - 9728 (black sun with rays).svg"
Otherwise yes you could split the command yourself and use a list. This is what I would do.
ยซ We can solve any problem by introducing an extra level of indirection ยป
Reply
#5
@Gribouillis: someone on linuxquestions.org also said "get rid of the spaces and disallowed characters" I gave the output file a simple name, but got the same FileNotFoundError

Using:

subprocess(command, shell=True)

works, but like I said, there is no colour, so I am back to square 1!

I will continue to fiddle!
Reply
#6
Orginal code in repo was not testet on Linux,it work on Windows,but not the colors.
Try this,testet on Linux๐ŸŽ‰
# export-all-emoji.py
import subprocess
import sys
import unicodedata
import re
from pathlib import Path

# defaults (can be overridden positionally)
INKSCAPE = "/usr/bin/inkscape"
FONT_PATH = "Segoe UI Emoji"
SYMBOL_TABLE = "symbol-table.csv"
OUT_DIR = "out"
SIZE = 256  # canvas size in pixels

def codepoint_to_char(cp_raw: str):
    cp = cp_raw.strip().upper()
    if cp.startswith("U+"):
        cp = cp[2:]
    if cp.startswith("0X"):
        cp = cp[2:]
    try:
        val = int(cp, 16)
        return chr(val)
    except Exception:
        raise ValueError(f"Invalid codepoint '{cp_raw}'")

def make_svg(emoji_char: str, font_path: str, size: int, font_size: int):
    return f"""<svg xmlns="http://www.w3.org/2000/svg" width="{size}" height="{size}" viewBox="0 0 {size} {size}">
        <style>
          @font-face {{
            font-family: CustomEmojiFont;
            src: url("{font_path}") format("truetype");
            }}
            text {{
              font-family: CustomEmojiFont, sans-serif;
              font-size: {font_size}px;
              dominant-baseline: hanging;
            }}
        </style>
        <text x="5" y="50">{emoji_char}</text>
        </svg>"""

def ascii_safe_name(s: str):
    # Decompose and strip diacritics
    decomposed = unicodedata.normalize("NFKD", s)
    stripped = "".join(
        ch for ch in decomposed
        if not unicodedata.category(ch).startswith("M")
    )
    # Replace non-alphanumeric, underscore, dash with underscore
    cleaned = re.sub(r"[^A-Za-z0-9_-]+", "_", stripped)
    cleaned = cleaned.strip("_")
    if not cleaned:
        # fallback to hex codes
        parts = [f"U{ord(ch):04X}" for ch in s]
        cleaned = "_".join(parts)
    return cleaned

def load_symbol_table(path: Path):
    with open(path, newline="", encoding="utf-8-sig") as f:
        sample = f.read(2048)
        f.seek(0)
        delimiter = ","
        if ";" in sample and sample.count(";") >= 1:
            delimiter = ";"
        reader = csv.reader(f, delimiter=delimiter)
        rows = list(reader)
    if not rows:
        return []

    header = [h.strip() for h in rows[0]]
    has_code_header = any(h.lower() == "code" for h in header)
    has_name_header = any(h.lower() == "name" for h in header)

    entries = []
    if has_code_header:
        with open(path, newline="", encoding="utf-8-sig") as f:
            reader2 = csv.DictReader(f, delimiter=delimiter)
            for row in reader2:
                code = row.get("code", "").strip()
                name = row.get("name", "").strip() if has_name_header else ""
                if code:
                    entries.append({"code": code, "name": name})
    else:
        for r in rows:
            if not r:
                continue
            if len(r) == 1 and ";" in r[0]:
                parts = r[0].split(";")
            else:
                parts = r
            code_candidate = None
            for p in parts:
                p_stripped = p.strip()
                if p_stripped.upper().startswith("U+"):
                    code_candidate = p_stripped
                    break
                if all(c in "0123456789ABCDEFabcdef" for c in p_stripped) and 2 <= len(p_stripped) <= 6:
                    code_candidate = p_stripped
                    break
            if not code_candidate:
                continue
            name_part = ""
            for p in parts:
                if p.strip() and p.strip() != code_candidate:
                    name_part = p.strip()
                    break
            entries.append({"code": code_candidate, "name": name_part})
    return entries

def main():
    global FONT_PATH, SYMBOL_TABLE, OUT_DIR, INKSCAPE
    if len(sys.argv) >= 2:
        FONT_PATH = sys.argv[1]
    if len(sys.argv) >= 3:
        SYMBOL_TABLE = sys.argv[2]
    if len(sys.argv) >= 4:
        OUT_DIR = sys.argv[3]
    if len(sys.argv) >= 5:
        INKSCAPE = sys.argv[4]

    out_dir = Path(OUT_DIR)
    out_dir.mkdir(parents=True, exist_ok=True)
    symbol_table_path = Path(SYMBOL_TABLE)
    if not symbol_table_path.exists():
        print(f"Error: symbol-table.csv not found at '{symbol_table_path}'", file=sys.stderr)
        sys.exit(1)
    font_ref = Path(FONT_PATH)
    font_url = font_ref.resolve().as_posix() if font_ref.exists() else FONT_PATH
    entries = load_symbol_table(symbol_table_path)
    if not entries:
        print("No valid entries found in symbol table.", file=sys.stderr)
        sys.exit(1)

    for entry in entries:
        raw_code = entry["code"]
        try:
            emoji_char = codepoint_to_char(raw_code)
        except ValueError as e:
            print(f"Skipping invalid codepoint '{raw_code}': {e}", file=sys.stderr)
            continue

        safe_code = raw_code.upper().replace("U+", "U+")
        if entry.get("name"):
            name_part = ascii_safe_name(entry["name"].strip())
            base = f"{safe_code}_{name_part}"
        else:
            base = safe_code
        temp_svg = out_dir / f"temp_{base}.svg"
        final_svg = out_dir / f"emoji_{base}.svg"
        svg_content = make_svg(emoji_char, font_url, SIZE, int(SIZE * 0.8))
        temp_svg.write_text(svg_content, encoding="utf-8")
        try:
            subprocess.run(
                [INKSCAPE, str(temp_svg), "--export-type=svg", "-o", str(final_svg)],
                check=True,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.PIPE,
            )
            print(f"Exported {final_svg.name}")
        except subprocess.CalledProcessError as e:
            print(f"Inkscape failed for {base}: {e.stderr.decode(errors='ignore')}", file=sys.stderr)
            temp_svg.replace(final_svg)
        finally:
            if temp_svg.exists():
                temp_svg.unlink()

if __name__ == "__main__":
    main()
Pedroski55 likes this post
Reply
#7
Thank you very much!

Gotta go to the dentist now Cry Cry Cry , will try it out later!
Reply
#8
@snippsat

I ran the programme in bash.

First, I needed to add:

import csv
and set my paths:

SYMBOL_TABLE = "/home/peterr/PVE/emoji2svg2png/symbol-table.csv"
#OUT_DIR = "out"
OUT_DIR = "/home/peterr/PVE/emoji2svg2png/svg/"
Your programme runs without error:

Output:
peterr@peterr-Modern-15-B7M:~/PVE/emoji2svg2png$ python3 export-all-emojiV3.py Exported emoji_2600_U2600.svg Exported emoji_1F95A_U1F95A.svg Exported emoji_2615_U2615.svg Exported emoji_1F601_U1F601.svg peterr@peterr-Modern-15-B7M:~/PVE/emoji2svg2png$
However, the output is incomplete, looks like only part of the emoji, and the parts that I can see are black, no colour to be seen.

I will go through each step in Idle, see if I can find a way to get coloured output!

But many thanks for your efforts!! Big Grin Big Grin Big Grin
Reply
#9
I think I found the problem, but I have no idea how to overcome it!

This is my original template file, after modification:

new_string

Output:
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n<svg\n width="265"\n height="265"\n viewBox="0 0 70.114582 70.114585"\n version="1.1"\n id="svg1909"\n xmlns="http://www.w3.org/2000/svg">\n <defs\n id="defs1906">\n <rect\n x="25.34241"\n y="41.74044"\n width="240.00753"\n height="177.39687"\n id="rect41737"/>\n <rect\n x="31.30533"\n y="49.19409"\n width="196.77636"\n height="168.45249"\n id="rect3710"/>\n </defs>\n <text\n xml:space="preserve"\n transform="matrix(0.26458333,0,0,0.26458333,0.76196943,27.023706)"\n id="text-box"\n style="font-style:normal;font-weight:normal;font-size:300px;line-height:0px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect3710);display:inline;fill:#000000;fill-opacity:1;stroke:none"\n x="56.777344"\n y="0"><tspan\n x="32.94043"\n y="135.39245"\n id="letter"><tspan\n style="font-family:\'NotoColorEmoji\';-inkscape-font-specification:\'NotoColorEmoji\';text-align:center;text-anchor:middle"\n id="tspan50637">โ˜€</tspan></tspan></text>\n</svg>\n'
If you look a style = you see:

Output:
style="font-style:normal;font-weight:normal;font-size:300px;line-height:0px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect3710);display:inline;fill:#000000;fill-opacity:1;stroke:none"
and you see:

Output:
fill:#000000
which is, I believe, black!

Any brilliant ideas how to overcome this??
Reply
#10
No you do not need to import csv and do not change anything other then your path to INKSCAPE.
Here some output how svg files look for me.
๐Ÿ˜Œ ๐Ÿšฃ ๐ŸŽ‹ ๐Ÿ˜
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Unable to resolve FileNotFoundError llarkin6 6 1,806 Sep-29-2025, 05:45 PM
Last Post: noisefloor
  Get an FFMpeg pass to subprocess.PIPE to treat list as text file? haihal 2 2,461 Nov-21-2024, 11:48 PM
Last Post: haihal
  FileNotFoundError: [Errno 2] No such file or directory although the file exists Arnibandyo 0 2,846 Aug-12-2024, 09:11 AM
Last Post: Arnibandyo
  "[Errno 2] No such file or directory" (.py file) IbrahimBennani 13 14,741 Jun-17-2024, 12:26 AM
Last Post: AdamHensley
  Error (Errno 2), File upload with the Flask framework and a public IP Username_Python1 0 2,050 Mar-28-2024, 01:46 PM
Last Post: Username_Python1
  Absolute paths in subprocess - file not found kittyticker 4 6,075 Jan-28-2024, 10:37 PM
Last Post: kittyticker
  FileNotFoundError: [WinError 2] The system cannot find the file specified NewBiee 2 3,973 Jul-31-2023, 11:42 AM
Last Post: deanhystad
  Using pyinstaller with .ui GUI files - No such file or directory error diver999 3 11,603 Jun-27-2023, 01:17 PM
Last Post: diver999
  Extract file only (without a directory it is in) from ZIPIP tester_V 1 5,877 Jan-23-2023, 04:56 AM
Last Post: deanhystad
  Running script with subprocess in another directory paul18fr 1 18,173 Jan-20-2023, 02:33 PM
Last Post: paul18fr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020