Commits

Chris Mutel  committed e1e56d8

Rearrange database.py in alphabetical order, and rename method

  • Participants
  • Parent commits 9b2e700

Comments (0)

Files changed (2)

File bw2data/database.py

             warnings.warn("\n\t%s not a currently installed database" % \
                 database, UserWarning)
 
-    @property
-    def version(self):
-        """The current version number (integer) of this database.
+    def __unicode__(self):
+        return u"Brightway2 database %s" % self.database
+
+    def __str__(self):
+        return unicode(self).encode('utf-8')
+
+    def backup(self):
+        """Save a backup to ``backups`` folder.
 
         Returns:
-            Version number
+            File path of backup.
 
         """
-        return databases.version(self.database)
-
-    def query(self, *queries):
-        """Search through the database. See :class:`query.Query` for details."""
-        return Query(*queries)(self.load())
-
-    def relabel_data(self, data, new_name):
-        """Relabel database keys and exchanges.
-
-        In a database which internally refer to the same database, update to new database name ``new_name``.
-
-        Needed to copy a database completely or cut out a section of a database.
-
-        For example:
-
-        .. code-block:: python
-
-            data = {
-                ("old and boring", 1):
-                    {"exchanges": [
-                        {"input": ("old and boring", 42),
-                        "amount": 1.0},
-                        ]
-                    },
-                ("old and boring", 2):
-                    {"exchanges": [
-                        {"input": ("old and boring", 1),
-                        "amount": 4.0}
-                        ]
-                    }
-                }
-            print relabel_database(data, "shiny new")
-            >> {
-                ("shiny new", 1):
-                    {"exchanges": [
-                        {"input": ("old and boring", 42),
-                        "amount": 1.0},
-                        ]
-                    },
-                ("shiny new", 2):
-                    {"exchanges": [
-                        {"input": ("shiny new", 1),
-                        "amount": 4.0}
-                        ]
-                    }
-                }
-
-        In the example, the exchange to ``("old and boring", 42)`` does not change, as this is not part of the updated data.
-
-        Args:
-            * *data* (dict): The database data to modify
-            * *new_name* (str): The name of the modified database
-
-        Returns:
-            The modified database
-
-        """
-        def relabel_exchanges(obj, new_name):
-            for e in obj['exchanges']:
-                if e["input"] in data:
-                    e["input"] = (new_name, e["input"][1])
-            return obj
-
-        return dict([((new_name, k[1]), relabel_exchanges(v, new_name)) \
-            for k, v in data.iteritems()])
+        from .io import BW2PackageExporter
+        return BW2PackageExporter.export_database(self.database,
+            folder="backups", extra_string="." + str(int(time()))
+            )
 
     def copy(self, name):
         """Make a copy of the database.
         new_database.write(data)
         return new_database
 
-    def backup(self):
-        """Save a backup to ``backups`` folder.
-
-        Returns:
-            Filepath of backup.
-
-        """
-        filepath = os.path.join(
-            config.request_dir("backups"),
-            self.filename() + ".%s.backup" % int(time())
-        )
-        with open(filepath, "wb") as f:
-            pickle.dump(self.load(), f, protocol=pickle.HIGHEST_PROTOCOL)
-        return filepath
-
-    def random(self):
-        """Return a random activity key.
-
-        Returns a random activity key, or ``None`` (and issues a warning) if the current database is empty."""
-        keys = self.load().keys()
-        if not keys:
-            warnings.warn("This database is empty")
-            return None
-        else:
-            return random.choice(keys)
-
-    def revert(self, version):
-        """Return data to a previous state.
-
-        .. warning:: Reverted changes can be overwritten.
-
-        Args:
-            * *version* (int): Number of the version to revert to.
-
-        """
-        assert version in [x[0] for x in self.versions()], "Version not found"
-        self.backup()
-        databases[self.database]["version"] = version
-        if config.p.get("use_cache", False) and self.database in config.cache:
-            config.cache[self.database] = self.load(version)
-        self.process(version)
-
-    def register(self, format, depends, num_processes, version=None):
-        """Register a database with the metadata store.
-
-        Databases must be registered before data can be written.
-
-        Args:
-            * *format* (str): Format that the database was converted from, e.g. "Ecospold"
-            * *depends* (list): Names of the databases that this database references, e.g. "biosphere"
-            * *num_processes* (int): Number of processes in this database.
-
-        """
-        assert self.database not in databases
-        databases[self.database] = {
-            "from format": format,
-            "depends": depends,
-            "number": num_processes,
-            "version": version or 0
-        }
-
     def deregister(self):
         """Remove a database from the metadata store. Does not delete any files."""
         del databases[self.database]
 
-    def validate(self, data):
-        """Validate data. Must be called manually.
-
-        Raises ``voluptuous.Invalid`` if data does not validate.
-
-        Args:
-            * *data* (dict): The data, in its processed form.
-
-        """
-        db_validator(data)
-
     def filename(self, version=None):
         """Filename for given version; Default is current.
 
             version or self.version
         )
 
-    def write(self, data):
-        """Serialize data to disk.
-
-        Args:
-            * *data* (dict): Inventory data
-
-        """
-        if self.database not in databases:
-            raise UnknownObject("This database is not yet registered")
-        databases.increment_version(self.database, len(data))
-        mapping.add(data.keys())
-        for ds in data.values():
-            ds["unit"] = normalize_units(ds["unit"])
-        geomapping.add([x["location"] for x in data.values() if
-                       x.get("location", False)])
-        if config.p.get("use_cache", False) and self.database in config.cache:
-            config.cache[self.database] = data
-        filepath = os.path.join(config.dir, "intermediate", self.filename())
-        with open(filepath, "wb") as f:
-            pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
-
     def load(self, version=None):
         """Load the intermediate data for this database.
 
         except OSError:
             raise MissingIntermediateData("This version (%i) not found" % version)
 
-    def versions(self):
-        """Get a list of available versions of this database.
-
-        Returns:
-            List of (version, datetime created) tuples.
-
-        """
-        directory = os.path.join(config.dir, "intermediate")
-        files = natural_sort(filter(
-            lambda x: ".".join(x.split(".")[:-2]) == self.database,
-            os.listdir(directory)))
-        return sorted([(int(name.split(".")[-2]),
-            datetime.datetime.fromtimestamp(os.stat(os.path.join(
-            config.dir, directory, name)).st_mtime)) for name in files])
-
     def process(self, version=None):
         """
 Process intermediate data from a Python dictionary to a `stats_arrays <https://pypi.python.org/pypi/stats_arrays/>`_ array, which is a `NumPy <http://numpy.scipy.org/>`_ `Structured <http://docs.scipy.org/doc/numpy/reference/generated/numpy.recarray.html#numpy.recarray>`_ `Array <http://docs.scipy.org/doc/numpy/user/basics.rec.html>`_. A structured array (also called record array) is a heterogeneous array, where each column has a different label and data type.
         with open(filepath, "wb") as f:
             pickle.dump(arr, f, protocol=pickle.HIGHEST_PROTOCOL)
 
-    def __unicode__(self):
-        return u"Brightway2 database %s" % self.database
+    def query(self, *queries):
+        """Search through the database. See :class:`query.Query` for details."""
+        return Query(*queries)(self.load())
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
+    def random(self):
+        """Return a random activity key.
+
+        Returns a random activity key, or ``None`` (and issues a warning) if the current database is empty."""
+        keys = self.load().keys()
+        if not keys:
+            warnings.warn("This database is empty")
+            return None
+        else:
+            return random.choice(keys)
+
+    def register(self, format, depends, num_processes, version=None):
+        """Register a database with the metadata store.
+
+        Databases must be registered before data can be written.
+
+        Args:
+            * *format* (str): Format that the database was converted from, e.g. "Ecospold"
+            * *depends* (list): Names of the databases that this database references, e.g. "biosphere"
+            * *num_processes* (int): Number of processes in this database.
+
+        """
+        assert self.database not in databases
+        databases[self.database] = {
+            "from format": format,
+            "depends": depends,
+            "number": num_processes,
+            "version": version or 0
+        }
+
+    def relabel_data(self, data, new_name):
+        """Relabel database keys and exchanges.
+
+        In a database which internally refer to the same database, update to new database name ``new_name``.
+
+        Needed to copy a database completely or cut out a section of a database.
+
+        For example:
+
+        .. code-block:: python
+
+            data = {
+                ("old and boring", 1):
+                    {"exchanges": [
+                        {"input": ("old and boring", 42),
+                        "amount": 1.0},
+                        ]
+                    },
+                ("old and boring", 2):
+                    {"exchanges": [
+                        {"input": ("old and boring", 1),
+                        "amount": 4.0}
+                        ]
+                    }
+                }
+            print relabel_database(data, "shiny new")
+            >> {
+                ("shiny new", 1):
+                    {"exchanges": [
+                        {"input": ("old and boring", 42),
+                        "amount": 1.0},
+                        ]
+                    },
+                ("shiny new", 2):
+                    {"exchanges": [
+                        {"input": ("shiny new", 1),
+                        "amount": 4.0}
+                        ]
+                    }
+                }
+
+        In the example, the exchange to ``("old and boring", 42)`` does not change, as this is not part of the updated data.
+
+        Args:
+            * *data* (dict): The database data to modify
+            * *new_name* (str): The name of the modified database
+
+        Returns:
+            The modified database
+
+        """
+        def relabel_exchanges(obj, new_name):
+            for e in obj['exchanges']:
+                if e["input"] in data:
+                    e["input"] = (new_name, e["input"][1])
+            return obj
+
+        return dict([((new_name, k[1]), relabel_exchanges(v, new_name)) \
+            for k, v in data.iteritems()])
+
+    def rename(self, name):
+        """Rename a database. Modifies exchanges to link to new name. Deregisters old database.
+
+        Args:
+            * *name* (str): New name.
+
+        Returns:
+            New ``Database`` object.
+
+        """
+        old_name = self.database
+        with warnings.catch_warnings():
+            warnings.simplefilter("ignore")
+            new_db = Database(name)
+            databases[name] = databases[old_name]
+        new_data = self.relabel_data(self.load(), name)
+        new_db.write(new_data)
+        new_db.process()
+        del databases[old_name]
+        return new_db
+
+    def revert(self, version):
+        """Return data to a previous state.
+
+        .. warning:: Reverted changes can be overwritten.
+
+        Args:
+            * *version* (int): Number of the version to revert to.
+
+        """
+        assert version in [x[0] for x in self.versions()], "Version not found"
+        self.backup()
+        databases[self.database]["version"] = version
+        if config.p.get("use_cache", False) and self.database in config.cache:
+            config.cache[self.database] = self.load(version)
+        self.process(version)
+
+    def validate(self, data):
+        """Validate data. Must be called manually.
+
+        Raises ``voluptuous.Invalid`` if data does not validate.
+
+        Args:
+            * *data* (dict): The data, in its processed form.
+
+        """
+        db_validator(data)
+
+    @property
+    def version(self):
+        """The current version number (integer) of this database.
+
+        Returns:
+            Version number
+
+        """
+        return databases.version(self.database)
+
+    def versions(self):
+        """Get a list of available versions of this database.
+
+        Returns:
+            List of (version, datetime created) tuples.
+
+        """
+        directory = os.path.join(config.dir, "intermediate")
+        files = natural_sort(filter(
+            lambda x: ".".join(x.split(".")[:-2]) == self.database,
+            os.listdir(directory)))
+        return sorted([(int(name.split(".")[-2]),
+            datetime.datetime.fromtimestamp(os.stat(os.path.join(
+            config.dir, directory, name)).st_mtime)) for name in files])
+
+    def write(self, data):
+        """Serialize data to disk.
+
+        Args:
+            * *data* (dict): Inventory data
+
+        """
+        if self.database not in databases:
+            raise UnknownObject("This database is not yet registered")
+        databases.increment_version(self.database, len(data))
+        mapping.add(data.keys())
+        for ds in data.values():
+            ds["unit"] = normalize_units(ds["unit"])
+        geomapping.add([x["location"] for x in data.values() if
+                       x.get("location", False)])
+        if config.p.get("use_cache", False) and self.database in config.cache:
+            config.cache[self.database] = data
+        filepath = os.path.join(config.dir, "intermediate", self.filename())
+        with open(filepath, "wb") as f:
+            pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)

File bw2data/tests/database.py

 from . import BW2DataTest
 from .. import Database, databases
 from ..errors import UnknownObject
+import copy
 from fixtures import food, biosphere
 
 
         d = Database("food")
         self.assertTrue(isinstance(str(d), str))
         self.assertTrue(isinstance(unicode(d), unicode))
+
+    def test_rename(self):
+        d = Database("biosphere")
+        d.register("Tests", [], len(biosphere))
+        d.write(biosphere)
+        d = Database("food")
+        d.register("Tests", ["biosphere"], len(food))
+        d.write(copy.deepcopy(food))
+        ndb = d.rename("buildings")
+        ndb_data = ndb.load()
+        self.assertEqual(ndb.database, "buildings")
+        self.assertEqual(len(ndb_data), len(food))
+        for key in ndb_data:
+            self.assertEqual(key[0], "buildings")
+            for exc in ndb_data[key]['exchanges']:
+                self.assertTrue(exc['input'][0] in ('biosphere', 'buildings'))