sumolib

  1# -*- coding: utf-8 -*-
  2# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
  3# Copyright (C) 2011-2026 German Aerospace Center (DLR) and others.
  4# This program and the accompanying materials are made available under the
  5# terms of the Eclipse Public License 2.0 which is available at
  6# https://www.eclipse.org/legal/epl-2.0/
  7# This Source Code may also be made available under the following Secondary
  8# Licenses when the conditions for such availability set forth in the Eclipse
  9# Public License 2.0 are satisfied: GNU General Public License, version 2
 10# or later which is available at
 11# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
 12# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
 13
 14# @file    __init__.py
 15# @author  Daniel Krajzewicz
 16# @author  Jakob Erdmann
 17# @author  Michael Behrisch
 18# @date    2011-06-23
 19
 20from __future__ import absolute_import
 21import os
 22import sys
 23import subprocess
 24import warnings
 25
 26from . import files, net, output, sensors, shapes, statistics, fpdiff  # noqa
 27from . import color, geomhelper, miscutils, options, route, vehicletype, version  # noqa
 28# the visualization submodule is not imported to avoid an explicit matplotlib dependency
 29from .miscutils import openz
 30from .options import pullOptions, ArgumentParser
 31from .version import _version as __version__  # noqa
 32from .xml import writeHeader as writeXMLHeader  # noqa
 33
 34
 35def saveConfiguration(executable, configoptions, filename):
 36    configoptions.save_configuration = filename
 37    call(executable, configoptions)
 38
 39
 40def call(executable, args):
 41    ap = ArgumentParser()
 42    pullOptions(executable, ap)
 43    cmd = [executable]
 44    for option, value in args.__dict__.items():
 45        o = "--" + option.replace("_", "-")
 46        if value is not None:
 47            a = ap.get_option(option)
 48            if a is not None and a.default != value:
 49                cmd.append(o)
 50                cmd.append(str(value))
 51    return subprocess.call(cmd)
 52
 53
 54def checkBinary(name, bindir=None):
 55    """
 56    Checks for the given binary in the places, defined by the environment
 57    variables SUMO_HOME and <NAME>_BINARY.
 58    """
 59
 60    def exe(binary):
 61        return binary + ".exe" if os.name == "nt" and binary[-4:] != ".exe" else binary
 62
 63    envName = "GUISIM_BINARY" if name == "sumo-gui" else name.upper() + "_BINARY"
 64    env = os.environ
 65    if envName in env and os.path.exists(exe(env[envName])):
 66        return exe(env[envName])
 67    if bindir is not None:
 68        binary = exe(os.path.join(bindir, name))
 69        if os.path.exists(binary):
 70            return binary
 71    if "SUMO_HOME" in env:
 72        binary = exe(os.path.join(env.get("SUMO_HOME"), "bin", name))
 73        if os.path.exists(binary):
 74            return binary
 75    try:
 76        import sumo
 77        # If there is a directory "sumo" in the current path, the import will succeed, so we need to double check.
 78        if hasattr(sumo, "SUMO_HOME"):
 79            binary = exe(os.path.join(sumo.SUMO_HOME, "bin", name))
 80            if os.path.exists(binary):
 81                return binary
 82    except ImportError:
 83        pass
 84    if bindir is None:
 85        binary = exe(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'bin', name)))
 86        if os.path.exists(binary):
 87            return binary
 88    if name[-1] != "D" and name[-5:] != "D.exe":
 89        binaryD = (name[:-4] if name[-4:] == ".exe" else name) + "D"
 90        found = checkBinary(binaryD, bindir)
 91        if found != binaryD:
 92            return found
 93    return name
 94
 95
 96class _Running:
 97
 98    """
 99    A generator of running, numerical IDs
100    Should be enhanced by:
101    - a member method for returning the size
102    - a member iterator over the stored ids
103    """
104
105    def __init__(self, orig_ids=False, warn=False):
106        """Contructor"""
107        # whether original IDs shall be used instead of an index
108        self.orig_ids = orig_ids
109        # whether a warning for non-integer IDs shall be given
110        self.warn = warn
111        # running index of assigned numerical IDs
112        self.index = 0
113        # map from known IDs to assigned numerical IDs
114        self._m = {}
115
116    def g(self, id):
117        """
118        If the given id is known, the numerical representation is returned,
119        otherwise a new running number is assigned to the id and returned"""
120        if id not in self._m:
121            if self.orig_ids:
122                self._m[id] = id
123                if self.warn:
124                    try:
125                        int(id)
126                    except ValueError:
127                        sys.stderr.write(
128                            'Warning: ID "%s" is not an integer.\n' % id)
129                        self.warn = False
130            else:
131                self._m[id] = self.index
132                self.index += 1
133        return self._m[id]
134
135    def k(self, id):
136        """
137        Returns whether the given id is known."""
138        return id in self._m
139
140    def d(self, id):
141        """
142        Removed the element."""
143        del self._m[id]
144
145
146class TeeFile:
147
148    """A helper class which allows simultaneous writes to several files"""
149
150    def __init__(self, *outputfiles):
151        self.files = outputfiles
152
153    def write(self, txt):
154        """Writes the text to all files"""
155        for fp in self.files:
156            fp.write(txt)
157
158    def flush(self):
159        """flushes all file contents to disc"""
160        for fp in self.files:
161            fp.flush()
162            if isinstance(fp, int) or hasattr(fp, "fileno"):
163                try:
164                    os.fsync(fp)
165                except OSError:
166                    pass
167
168    def close(self):
169        """closes all closable outputs"""
170        for fp in self.files:
171            if fp not in (sys.__stdout__, sys.__stderr__) and hasattr(fp, "close"):
172                fp.close()
173
174
175def _intTime(tStr):
176    """
177    Converts a time given as a string containing a float into an integer representation.
178    """
179    return int(float(tStr))
180
181
182def _laneID2edgeID(laneID):
183    return laneID[:laneID.rfind("_")]
184
185
186def open(fileOrURL, tryGZip=True, mode="rb"):
187    warnings.warn("sumolib.open is deprecated, due to the name clash and strange signature! "
188                  "Use sumolib.miscutils.openz instead.")
189    return openz(fileOrURL, mode, tryGZip=tryGZip)
def saveConfiguration(executable, configoptions, filename):
36def saveConfiguration(executable, configoptions, filename):
37    configoptions.save_configuration = filename
38    call(executable, configoptions)
def call(executable, args):
41def call(executable, args):
42    ap = ArgumentParser()
43    pullOptions(executable, ap)
44    cmd = [executable]
45    for option, value in args.__dict__.items():
46        o = "--" + option.replace("_", "-")
47        if value is not None:
48            a = ap.get_option(option)
49            if a is not None and a.default != value:
50                cmd.append(o)
51                cmd.append(str(value))
52    return subprocess.call(cmd)
def checkBinary(name, bindir=None):
55def checkBinary(name, bindir=None):
56    """
57    Checks for the given binary in the places, defined by the environment
58    variables SUMO_HOME and <NAME>_BINARY.
59    """
60
61    def exe(binary):
62        return binary + ".exe" if os.name == "nt" and binary[-4:] != ".exe" else binary
63
64    envName = "GUISIM_BINARY" if name == "sumo-gui" else name.upper() + "_BINARY"
65    env = os.environ
66    if envName in env and os.path.exists(exe(env[envName])):
67        return exe(env[envName])
68    if bindir is not None:
69        binary = exe(os.path.join(bindir, name))
70        if os.path.exists(binary):
71            return binary
72    if "SUMO_HOME" in env:
73        binary = exe(os.path.join(env.get("SUMO_HOME"), "bin", name))
74        if os.path.exists(binary):
75            return binary
76    try:
77        import sumo
78        # If there is a directory "sumo" in the current path, the import will succeed, so we need to double check.
79        if hasattr(sumo, "SUMO_HOME"):
80            binary = exe(os.path.join(sumo.SUMO_HOME, "bin", name))
81            if os.path.exists(binary):
82                return binary
83    except ImportError:
84        pass
85    if bindir is None:
86        binary = exe(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'bin', name)))
87        if os.path.exists(binary):
88            return binary
89    if name[-1] != "D" and name[-5:] != "D.exe":
90        binaryD = (name[:-4] if name[-4:] == ".exe" else name) + "D"
91        found = checkBinary(binaryD, bindir)
92        if found != binaryD:
93            return found
94    return name

Checks for the given binary in the places, defined by the environment variables SUMO_HOME and _BINARY.

class TeeFile:
147class TeeFile:
148
149    """A helper class which allows simultaneous writes to several files"""
150
151    def __init__(self, *outputfiles):
152        self.files = outputfiles
153
154    def write(self, txt):
155        """Writes the text to all files"""
156        for fp in self.files:
157            fp.write(txt)
158
159    def flush(self):
160        """flushes all file contents to disc"""
161        for fp in self.files:
162            fp.flush()
163            if isinstance(fp, int) or hasattr(fp, "fileno"):
164                try:
165                    os.fsync(fp)
166                except OSError:
167                    pass
168
169    def close(self):
170        """closes all closable outputs"""
171        for fp in self.files:
172            if fp not in (sys.__stdout__, sys.__stderr__) and hasattr(fp, "close"):
173                fp.close()

A helper class which allows simultaneous writes to several files

TeeFile(*outputfiles)
151    def __init__(self, *outputfiles):
152        self.files = outputfiles
files
def write(self, txt):
154    def write(self, txt):
155        """Writes the text to all files"""
156        for fp in self.files:
157            fp.write(txt)

Writes the text to all files

def flush(self):
159    def flush(self):
160        """flushes all file contents to disc"""
161        for fp in self.files:
162            fp.flush()
163            if isinstance(fp, int) or hasattr(fp, "fileno"):
164                try:
165                    os.fsync(fp)
166                except OSError:
167                    pass

flushes all file contents to disc

def close(self):
169    def close(self):
170        """closes all closable outputs"""
171        for fp in self.files:
172            if fp not in (sys.__stdout__, sys.__stderr__) and hasattr(fp, "close"):
173                fp.close()

closes all closable outputs

def open(fileOrURL, tryGZip=True, mode='rb'):
187def open(fileOrURL, tryGZip=True, mode="rb"):
188    warnings.warn("sumolib.open is deprecated, due to the name clash and strange signature! "
189                  "Use sumolib.miscutils.openz instead.")
190    return openz(fileOrURL, mode, tryGZip=tryGZip)