Changeset 3732:6d390fd934e0 in livinglogic.python.xist

Show
Ignore:
Timestamp:
04/02/09 18:37:22 (10 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Merge orasql into xist. Drop unneccessary make actions. Add proper oracle URLs to ll.url.

Files:
18 added
10 modified

Legend:

Unmodified
Added
Removed
  • INSTALL.rst

    r3612 r3732  
    1313        :func:`ll.xist.ns.html.astext`); 
    1414 
    15     5.  `setuptools`_ (if you want to install this package as an egg); 
     15    5.  `cx_Oracle`_ (if you want to use :mod:`ll.orasql`); 
    1616 
    17     6.  `py.test`_ (if you want to run the test suite) 
     17    6.  `setuptools`_ (if you want to install this package as an egg); 
    1818 
    19     7.  and a C compiler supported by distutils, if you want to install the 
     19    7.  `py.test`_ (if you want to run the test suite) 
     20 
     21    8.  and a C compiler supported by distutils, if you want to install the 
    2022        source distribution. 
    2123 
     
    2426    .. _libxml2: http://www.xmlsoft.org/ 
    2527    .. _elinks: http://elinks.or.cz/ 
     28    .. _cx_Oracle: http://cx-oracle.sourceforge.net/ 
    2629    .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools 
    2730    .. _py.test: http://codespeak.net/py/current/doc/test.html 
  • NEWS.rst

    r3730 r3732  
    22------------------------------------ 
    33 
     4*   :mod:`ll.make` has a new Action class: :class:`ObjectAction` that simply 
     5    returns a fixed object. 
     6 
     7*   The following classes have been removed from :mod:`ll.make`: 
     8    :class:`EncodeAction`, :class:`DecodeAction`, :class:`EvalAction`, 
     9    :class:`GZipAction`, :class:`GUnzipAction`, 
     10    :class:`JavascriptMinifyAction`, :class:`XISTBytesAction`, 
     11    :class:`XISTStringAction`, :class:`JoinAction`, :class:`UnpickleAction`, 
     12    :class:`PickleAction`, :class:`TOXICAction`, :class:`TOXICPrettifyAction`, 
     13    :class:`SplatAction`, :class:`UL4CompileAction`, :class:`UL4RenderAction`, 
     14    :class:`UL4DumpAction` and :class:`UL4LoadAction`. All of these actions can 
     15    be executed by using :class:`CallAction` or :class:`CallAttrAction`. 
     16 
     17*   :class:`ll.make.PipeAction` has been renamed to :class:`TransformAction`. 
     18 
     19*   The new :class:`ll.make.PipeAction` pipes the input through an external 
     20    command. 
     21 
     22*   :class:`ll.make.FileAction` now automatically wraps the :var:`key` argument 
     23    into an :class:`URL` object. 
     24 
    425*   The division operator is no longer implemented for :class:`Action` objects 
    526    in :mod:`ll.make`. 
    627 
    7 *   :mod:`ll.make` has two new action classes: :class:`JSONEncodeAction` and 
    8     :class:`JSONDecodeAction`. 
     28*   The script ``ucp`` now changes the user and group only if a user or group is 
     29    given. 
    930 
    1031 
  • OLDNEWS.rst

    r3625 r3732  
    15981598 
    15991599*   Initial release. 
     1600 
     1601 
     1602Changes to ll-orasql 
     1603#################### 
     1604 
     1605Changes in ll-orasql 1.27.1 (released 03/31/2009) 
     1606------------------------------------------------- 
     1607 
     1608*   Fixed a bug in the dependency checking for :meth:`Connnection.itertables`. 
     1609 
     1610*   ``oradelete`` now has a new option to use ``truncate table`` instead of 
     1611    ``delete from``. 
     1612 
     1613 
     1614Changes in ll-orasql 1.27 (released 03/31/2009) 
     1615----------------------------------------------- 
     1616 
     1617*   Added a new script ``oradelete`` that can be used to delete all records from 
     1618    all tables and to reset all sequences. 
     1619 
     1620*   :class:`Connection` has a new method :meth:`itersequences`. 
     1621 
     1622*   Fixed a bug in the generated SQl code for triggers (the name always included 
     1623    the name of the original schema). 
     1624 
     1625 
     1626Changes in ll-orasql 1.26 (released 03/27/2009) 
     1627----------------------------------------------- 
     1628 
     1629*   :mod:`ll.orasql` now requires cx_Oracle 5.0 compiled in Unicode mode 
     1630    (i.e. with ``WITH_UNICODE=1``). Lots of unicode handling stuff has been 
     1631    rewritten to take advantage of Unicode mode. 
     1632 
     1633*   ``orafind`` has a new option ``--encoding`` to decode the searchstring on the 
     1634    commandline. 
     1635 
     1636*   The :class:`Pool` constructor now supports the additional arguments 
     1637    :var:`getmode` and :var:`homogeneous` from cx_Oracle 5.0. 
     1638 
     1639*   Fix a typo in :meth:`Privilege.grantddl`. 
     1640 
     1641 
     1642Changes in ll-orasql 1.25.4 (released 01/21/2009) 
     1643------------------------------------------------- 
     1644 
     1645*   Procedures and functions with timestamp arguments can now be called. 
     1646 
     1647 
     1648Changes in ll-orasql 1.25.3 (released 11/07/2008) 
     1649------------------------------------------------- 
     1650 
     1651*   Procedures and functions now should handle arguments of type ``BLOB`` 
     1652    correctly. 
     1653 
     1654 
     1655Changes in ll-orasql 1.25.2 (released 08/29/2008) 
     1656------------------------------------------------- 
     1657 
     1658*   :class:`Record` has a new method :meth:`get` which works like the dictionary 
     1659    method :meth:`get`. 
     1660 
     1661 
     1662Changes in ll-orasql 1.25.1 (released 07/21/2008) 
     1663------------------------------------------------- 
     1664 
     1665*   ``orafind.py`` now has an additional options :option:`readlobs` (defaulting 
     1666    to false). If this option is set, the value of LOBs in the records found, 
     1667    will be printed. 
     1668 
     1669 
     1670Changes in ll-orasql 1.25 (released 06/17/2008) 
     1671----------------------------------------------- 
     1672 
     1673*   A new script has been added: ``orafind.py`` will search for a specified 
     1674    string in all columns of all tables in a schema. 
     1675 
     1676 
     1677Changes in ll-orasql 1.24.1 (released 05/30/2008) 
     1678------------------------------------------------- 
     1679 
     1680*   Fixed two bugs in :meth:`Callable._calcargs` and :meth:`Connection.getobject`. 
     1681 
     1682 
     1683Changes in ll-orasql 1.24 (released 05/20/2008) 
     1684----------------------------------------------- 
     1685 
     1686*   :meth:`Connection.getobject`, :class:`Procedure` and :class:`Function` now 
     1687    support functions and procedures in packages. 
     1688 
     1689*   Added :meth:`__repr__` to the exception classes. 
     1690 
     1691 
     1692Changes in ll-orasql 1.23.4 (released 04/04/2008) 
     1693------------------------------------------------- 
     1694 
     1695*   All database scripts now have an additional option :option:`encoding` that 
     1696    specifies the encoding for the output script. 
     1697 
     1698 
     1699Changes in ll-orasql 1.23.3 (released 04/03/2008) 
     1700------------------------------------------------- 
     1701 
     1702*   Fixed a regression in the scripts ``oracreate.py``, ``oradrop.py`` and 
     1703    ``oragrant.py``. 
     1704 
     1705 
     1706Changes in ll-orasql 1.23.2 (released 04/01/2008) 
     1707------------------------------------------------- 
     1708 
     1709*   When calling functions/procedures, arguments are now wrapped in variable 
     1710    objects for their real type instead of ones for the type the function or 
     1711    procedure expects. 
     1712 
     1713 
     1714Changes in ll-orasql 1.23.1 (released 03/25/2008) 
     1715------------------------------------------------- 
     1716 
     1717*   Added a :meth:`__contains__` to :class:`Record` for checking the existence 
     1718    of a field. 
     1719 
     1720 
     1721Changes in ll-orasql 1.23 (released 03/25/2008) 
     1722----------------------------------------------- 
     1723 
     1724*   Calling procedures and functions has been rewritten: :mod:`ll.orasql` will 
     1725    only pass those parameters to the procedure/function that are passed to the 
     1726    call (or variables for out parameters). Internally this is handled by 
     1727    executing the call as a parameterized query calling the procedure/function 
     1728    with named arguments. 
     1729 
     1730*   :class:`FetchRecord` has been renamed to :class:`Record` (and is used for 
     1731    the result of procedure and function calls now, which required some internal 
     1732    changes to :class:`FetchRecord`). The former :class:`Record` has been renamed 
     1733    to :class:`Args` as its only use now is collecting arguments for 
     1734    procedure/function calls. (The method :meth:`fromdata` has been dropped.) 
     1735 
     1736*   The :meth:`__repr__` output of :class:`Argument` objects now shows the 
     1737    datatype. 
     1738 
     1739 
     1740Changes in ll-orasql 1.22 (released 03/19/2008) 
     1741----------------------------------------------- 
     1742 
     1743*   Added a new method :meth:`_getobject` to :class:`Connection` that does 
     1744    what :meth:`getobject` does, but is case sensitive (This is used internally 
     1745    by :meth:`Synonym.getobject`). 
     1746 
     1747*   The methods :meth:`xfetchone`, :meth:`xfetchmany`, :meth:`xfetchall`, 
     1748    :meth:`xfetch`, :meth:`xexecute` and :meth:`xexecutemany` have been dropped 
     1749    again. Fetch result objects are now of type :class:`FetchRecord`. Field 
     1750    access is available via index (i.e. ``row[0]``), key (``row["name"]``) 
     1751    and attribute (``row.name``). These result objects are generated via the 
     1752    :attr:`rowfactory` attribute (which was added in cx_Oracle 4.3.2). 
     1753    All fetch and execute methods support unicode values. 
     1754 
     1755 
     1756Changes in ll-orasql 1.21.1 (released 03/17/2008) 
     1757------------------------------------------------- 
     1758 
     1759*   Updated the scripts to work with the new execute methods. 
     1760 
     1761 
     1762Changes in ll-orasql 1.21 (released 03/13/2008) 
     1763----------------------------------------------- 
     1764 
     1765*   :class:`Connection` has a new method :meth:`getobject`, which returns the 
     1766    schema object with a specified name. 
     1767 
     1768*   :class:`Synonym` has a new method :meth:`getobject`, that returns the object 
     1769    for which the :class:`Synonym` object is a synonym. 
     1770 
     1771*   The name of :class:`Procedure` and :class:`Function` objects now is case 
     1772    sensitive when calling the procedure or function. 
     1773 
     1774 
     1775 
     1776Changes in ll-orasql 1.20 (released 02/07/2008) 
     1777----------------------------------------------- 
     1778 
     1779*   The fancy fetch methods have been renamed to :meth:`xfetchone`, 
     1780    :meth:`xfetchmany`, :meth:`xfetchall` and :meth:`xfetch`. :meth:`__iter__` 
     1781    no longer gets overwritten. New methods :meth:`xexecute` and 
     1782    :meth:`xexecutemany` have been added, that support passing unicode 
     1783    parameters. 
     1784 
     1785 
     1786Changes in ll-orasql 1.19 (released 02/01/2008) 
     1787----------------------------------------------- 
     1788 
     1789*   All docstrings use ReST now. 
     1790 
     1791 
     1792Changes in ll-orasql 1.18 (released 01/07/2008) 
     1793----------------------------------------------- 
     1794 
     1795*   Updated the docstrings to XIST 3.0. 
     1796 
     1797*   Added ReST versions of the documentation. 
     1798 
     1799 
     1800Changes in ll-orasql 1.17.5 (released 08/09/2007) 
     1801------------------------------------------------- 
     1802 
     1803*   Fixed a bug in the error handling of wrong arguments when calling 
     1804    functions or procedures. 
     1805 
     1806 
     1807Changes in ll-orasql 1.17.4 (released 04/30/2007) 
     1808------------------------------------------------- 
     1809 
     1810*   The threshold for string length for procedure and function arguments has 
     1811    been reduced to 4000. 
     1812 
     1813 
     1814Changes in ll-orasql 1.17.3 (released 03/08/2007) 
     1815------------------------------------------------- 
     1816 
     1817*   ``BLOB`` arguments for procedures and functions are always passed as 
     1818    variables now. 
     1819 
     1820 
     1821Changes in ll-orasql 1.17.2 (released 03/07/2007) 
     1822------------------------------------------------- 
     1823 
     1824*   Arguments for procedures and functions that are longer that 32000 characters 
     1825    are passed as variables now (the threshold was 32768 before and didn't work). 
     1826 
     1827 
     1828Changes in ll-orasql 1.17.1 (released 03/02/2007) 
     1829------------------------------------------------- 
     1830 
     1831*   Fix an inverted logic bug in :meth:`Record.fromdata` that surfaced in unicode 
     1832    mode: ``BLOB``\s were treated as string and ``CLOB``\s as binary data. 
     1833 
     1834 
     1835Changes in ll-orasql 1.17 (released 02/23/2007) 
     1836----------------------------------------------- 
     1837 
     1838*   The :var:`readlobs` and :var:`unicode` parameters are now honored when 
     1839    calling procedures and functions via :class:`Procedure` and 
     1840    :class:`Function` objects. 
     1841 
     1842 
     1843Changes in ll-orasql 1.16 (released 02/21/2007) 
     1844----------------------------------------------- 
     1845 
     1846*   A parameter :var:`unicode` has been added to various constructors and methods. 
     1847    This parameter can be used to get strings (i.e. ``VARCHAR2`` and ``CLOB``\s) 
     1848    as :class:`unicode` object instead of :class:`str` objects. 
     1849 
     1850 
     1851Changes in ll-orasql 1.15 (released 02/17/2007) 
     1852----------------------------------------------- 
     1853 
     1854*   Fixed an output bug in ``oradiff.py`` when running in full output mode. 
     1855 
     1856*   A parameter :var:`readlobs` has been added to various constructors and 
     1857    methods that can be used to get small (or all) ``LOB`` values as strings in 
     1858    cursor fetch calls. 
     1859 
     1860 
     1861Changes in ll-orasql 1.14 (released 02/01/2007) 
     1862----------------------------------------------- 
     1863 
     1864*   A new method :meth:`iterprivileges` has been added to :class:`Connection`. 
     1865 
     1866*   A script ``oragrant.py`` has been added for copying privileges. 
     1867 
     1868 
     1869Changes in ll-orasql 1.13 (released 11/06/2006) 
     1870----------------------------------------------- 
     1871 
     1872*   Two new methods (:meth:`itertables` and :meth:`iterfks`) have been added to 
     1873    :class:`Connection`. They yield all table definitions or all foreign keys 
     1874    respectively. 
     1875 
     1876*   A new method :meth:`isenabled` has been added to :class:`ForeignKey`. 
     1877 
     1878*   A :meth:`__str__` method has been added to :class:`Object`. 
     1879 
     1880*   A bug in ``oramerge.py`` has been fixed: In certain situations ``oramerge.py`` 
     1881    used merging actions that were meant to be used for the preceeding object. 
     1882 
     1883 
     1884Changes in ll-orasql 1.12.2 (released 10/18/2006) 
     1885------------------------------------------------- 
     1886 
     1887*   Fixed a bug that showed up when an index and a foreign key of the same name 
     1888    existed. 
     1889 
     1890 
     1891Changes in ll-orasql 1.12.1 (released 09/19/2006) 
     1892------------------------------------------------- 
     1893 
     1894*   Fixed a bug in :meth:`Index.__xattrs__`. 
     1895 
     1896 
     1897Changes in ll-orasql 1.12 (released 09/06/2006) 
     1898----------------------------------------------- 
     1899 
     1900*   :class:`Function` objects are now callable too. They return the return value 
     1901    and a :class:`Record` containing the modified input parameters. 
     1902 
     1903 
     1904Changes in ll-orasql 1.11.1 (released 08/29/2006) 
     1905------------------------------------------------- 
     1906 
     1907*   Fixed a bug in :meth:`Column.modifyddl`. 
     1908 
     1909 
     1910Changes in ll-orasql 1.11 (released 08/22/2006) 
     1911----------------------------------------------- 
     1912 
     1913*   The class :class:`Column` has gained a few new methods: :meth:`datatype`, 
     1914    :meth:`default`, :meth:`nullable` and :meth:`comment`. 
     1915 
     1916*   Calling a procedure will now raise a :class:`SQLObjectNotFoundError` error, 
     1917    if the procedure doesn't exist. 
     1918 
     1919 
     1920Changes in ll-orasql 1.10 (released 08/11/2006) 
     1921----------------------------------------------- 
     1922 
     1923*   The classes :class:`Proc` and :class:`LLProc` have been removed. The 
     1924    functionality of :class:`Proc` has been merged into 
     1925    :class:`ProcedureDefinition` (with has been renamed to :class:`Procedure`). 
     1926    Information about the procedure arguments is provided by the 
     1927    :meth:`iteraguments` method. 
     1928 
     1929*   All other subclasses of :class:`Definition` have been renamed to remove the 
     1930    "Definition" for the name to reduce typing. (Methods have been renamed 
     1931    accordingly too.)</li> 
     1932 
     1933*   :func:`oramerge.main` and :func:`oradiff.main` now accept option arrays as 
     1934    arguments. 
     1935 
     1936*   ``oradiff.py`` has finally been fixed. 
     1937 
     1938 
     1939Changes in ll-orasql 1.9.4 (released 08/09/2006) 
     1940------------------------------------------------ 
     1941 
     1942*   Fixed a bug in ``oradiff.py``. 
     1943 
     1944 
     1945Changes in ll-orasql 1.9.3 (released 08/08/2006) 
     1946------------------------------------------------ 
     1947 
     1948*   Fixed a bug in ``oramerge.py``. 
     1949 
     1950 
     1951Changes in ll-orasql 1.9.2 (released 08/04/2006) 
     1952------------------------------------------------ 
     1953 
     1954*   Fixed a bug in :meth:`TableDefinition.iterdefinitions`. 
     1955 
     1956 
     1957Changes in ll-orasql 1.9.1 (released 08/02/2006) 
     1958------------------------------------------------ 
     1959 
     1960*   Fixed a bug in ``oracreate.py``. 
     1961 
     1962 
     1963Changes in ll-orasql 1.9 (released 07/24/2006) 
     1964---------------------------------------------- 
     1965 
     1966*   Dependencies involving :class:`MaterializedViewDefinition` and 
     1967    :class:`IndexDefinition` objects generated by constraints work properly now, 
     1968    so that iterating all definitions in create order really results in a 
     1969    working SQL script. 
     1970 
     1971*   A method :meth:`table` has been added to :class:`PKDefinition`, 
     1972    :class:`FKDefinition`, :class:`UniqueDefinition` and 
     1973    :class:`IndexDefinition`. This method returns the :class:`TableDefinition` to 
     1974    object belongs to. 
     1975 
     1976*   A method :meth:`pk` has been added to :class:`FKDefinition`. It returns the 
     1977    primary key that this foreign key references. 
     1978 
     1979*   Indexes and constraints belonging to skipped tables are now skipped too in 
     1980    ``oracreate.py``. 
     1981 
     1982*   Arguments other than ``sys.argv[1:]`` can now be passed to the 
     1983    ``oracreate.py`` and ``oradrop.py`` :func:`main` functions. 
     1984 
     1985 
     1986Changes in ll-orasql 1.8.1 (released 07/17/2006) 
     1987------------------------------------------------ 
     1988 
     1989*   :mod:`ll.orasql` can now handle objects name that are not in uppercase. 
     1990 
     1991 
     1992Changes in ll-orasql 1.8 (released 07/14/2006) 
     1993---------------------------------------------- 
     1994 
     1995*   :meth:`Connection.iterobjects` has been renamed to :meth:`iterdefinitions`. 
     1996 
     1997*   Each :class:`Definition` subclass has a new classmethod 
     1998    :meth:`iterdefinitions` that iterates through all definitions of this type 
     1999    in a schema (or all schemas). 
     2000 
     2001*   Each :class:`Definition` subclass has new methods :meth:`iterreferences` and 
     2002    :meth:`iterreferencedby` that iterate through related definitions. The 
     2003    methods :meth:`iterreferencesall` and :meth:`iterreferencedbyall` do this 
     2004    recursively. The method :meth:`iterdependent` is gone now. 
     2005 
     2006*   The method :meth:`iterschema` of :class:`Connection` now has an additional 
     2007    parameter :var:`schema`. Passing ``"all"`` for :var:`schema` will give you 
     2008    statistics for the complete database not just one schema. 
     2009 
     2010*   A new definition class :class:`MaterializedViewDefinition` has been added 
     2011    that handles materialized views. Handling of create options is rudimentary 
     2012    though. Patches are welcome. 
     2013 
     2014*   :class:`TableDefinition` has a three new methods: :meth:`ismview` returns 
     2015    whether the table is a materialized view; :meth:`itercomments` iterates 
     2016    through comments and :meth:`iterconstraints` iterates through primary keys, 
     2017    foreign keys and unique constraints. 
     2018 
     2019*   The method :meth:`getcursor` will now raise a :class:`TypeError` if it can't 
     2020    get a cursor. 
     2021 
     2022 
     2023Changes in ll-orasql 1.7.2 (released 07/05/2006) 
     2024------------------------------------------------ 
     2025 
     2026*   ``RAW`` fields in tables are now output properly in 
     2027    :meth:`TableDefinition.createddl`. 
     2028 
     2029*   A class :class:`PackageBodyDefinition` has been added. ``oracreate.py`` will 
     2030    output package body definitions and ``oradrop.py`` will drop them. 
     2031 
     2032 
     2033Changes in ll-orasql 1.7.1 (released 07/04/2006) 
     2034------------------------------------------------ 
     2035 
     2036*   Duplicate code in the scripts has been removed. 
     2037 
     2038*   Fixed a bug in ``oramerge.py``: If the source to be diffed was long enough 
     2039    the call to ``diff3`` deadlocked. 
     2040 
     2041 
     2042Changes in ll-orasql 1.7 (released 06/29/2006) 
     2043---------------------------------------------- 
     2044 
     2045*   The method :meth:`iterobjects` has been moved from :class:`Cursor` to 
     2046    :class:`Connection`. 
     2047 
     2048*   The method :meth:`itercolumns` has been moved from :class:`Cursor` to 
     2049    :class:`TableDefinition`. 
     2050 
     2051*   :class:`LLProc` now recognizes the ``c_out`` parameter used by 
     2052    :mod:`ll.toxic` 0.8. 
     2053 
     2054*   Support for positional arguments has been added for :class:`Proc` and 
     2055    :class:`LLProc`. Error messages for calling procedures have been enhanced. 
     2056 
     2057*   :class:`SequenceDefinition` now has a new method :meth:`createddlcopy` that 
     2058    returns code that copies the sequence value. ``oracreate.py`` has a new 
     2059    option :option:`-s`/:option:`--seqcopy` that uses this feature. 
     2060 
     2061*   :mod:`setuptools` is now supported for installation. 
     2062 
     2063 
     2064Changes in ll-orasql 1.6 (released 04/26/2006) 
     2065---------------------------------------------- 
     2066 
     2067*   Added a :class:`SessionPool` (a subclass of :class:`SessionPool` in 
     2068    :mod:`cx_Oracle`) whose :meth:`acquire` method returns 
     2069    :mod:`ll.orasql.Connection` objects. 
     2070 
     2071 
     2072Changes in ll-orasql 1.5 (released 04/05/2006) 
     2073---------------------------------------------- 
     2074 
     2075*   Added a class :class:`IndexDefinition` for indexes. ``oracreate.py`` will 
     2076    now issue create statements for indexes. 
     2077 
     2078 
     2079Changes in ll-orasql 1.4.3 (released 12/07/2005) 
     2080------------------------------------------------ 
     2081 
     2082*   Fixed a bug with empty lines in procedure sources. 
     2083 
     2084*   Remove spurious spaces at the start of procedure and function definitions. 
     2085 
     2086 
     2087Changes in ll-orasql 1.4.2 (released 12/07/2005) 
     2088------------------------------------------------ 
     2089 
     2090*   Fixed a bug that the DDL output of Java source. 
     2091 
     2092*   Trailing whitespace in each line of procedures, functions etc. is now stripped. 
     2093 
     2094 
     2095Changes in ll-orasql 1.4.1 (released 12/06/2005) 
     2096------------------------------------------------ 
     2097 
     2098*   Fixed a bug that resulted in omitted field lengths. 
     2099 
     2100 
     2101Changes in ll-orasql 1.4 (released 12/05/2005) 
     2102---------------------------------------------- 
     2103 
     2104*   The option :option:`-m`/:option:`--mode` has been dropped from the script 
     2105    ``oramerge.py``. 
     2106 
     2107*   A new class :class:`ColumnDefinition` has been added to :mod:`ll.orasql`. 
     2108    The :class:`Cursor` class has a new method :meth:`itercolumns` that iterates 
     2109    the :class:`ColumnDefinition` objects of a table. 
     2110 
     2111*   ``oramerge.py`` now doesn't output a merged ``create table`` statement, but 
     2112    the appropriate ``alter table`` statements. 
     2113 
     2114 
     2115Changes in ll-orasql 1.3 (released 11/24/2005) 
     2116---------------------------------------------- 
     2117 
     2118*   Added an option :option:`-i` to ``oracreate.py`` and ``oradrop.py`` to 
     2119    ignore errors. 
     2120 
     2121*   The argument :var:`all` of the cursor method :meth:`iterobjects` is now 
     2122    named :var:`schema` and may have three values: ``"own"``, ``"dep"`` and 
     2123    ``"all"``. 
     2124 
     2125*   Added an script ``oramerge.py`` that does a three way merge of three database 
     2126    schemas and outputs the resulting script. 
     2127 
     2128*   DB links are now copied over in :class:`SynonymDefinition` objects. 
     2129 
     2130 
     2131Changes in ll-orasql 1.2 (released 10/24/2005) 
     2132---------------------------------------------- 
     2133 
     2134*   Added a argument to :meth:`createddl` and :meth:`dropddl` to specify if 
     2135    terminated or unterminated DDL is wanted (i.e. add ``;`` or ``/`` or not). 
     2136 
     2137*   :class:`CommentsDefinition` has been renamed to :class:`CommentDefinition` 
     2138    and holds the comment for one field only. 
     2139 
     2140*   :class:`JavaSourceDefinition` has been added. 
     2141 
     2142*   The scripts ``oracreate.py``, ``oradrop.py`` and ``oradiff.py`` now skip 
     2143    objects with ``"$"`` in their name by default. This can be changed with the 
     2144    :option:`-k` option (but this will lead to unexecutable scripts). 
     2145 
     2146*   ``oradiff.py`` has a new options :option:`-b`: This allows you to specify 
     2147    how whitespace should be treated. 
     2148 
     2149*   Added an option :option:`-x` to ``oracreate.py`` to make it possible to 
     2150    directly execute the DDL in another database. 
     2151 
     2152*   Fixed a bug in :class:`SequenceDefinition` when the ``CACHE`` field was ``0``. 
     2153 
     2154 
     2155Changes in ll-orasql 1.1 (released 10/20/2005) 
     2156---------------------------------------------- 
     2157 
     2158*   A script ``oradiff.py`` has been added which can be used for diffing Oracle 
     2159    schemas. 
     2160 
     2161*   Definition classes now have two new methods :meth:`cdate` and :meth:`udate` 
     2162    that give the creation and modification time of the schema object 
     2163    (if available). 
     2164 
     2165*   A ``"flat"`` iteration mode has been added to :meth:`Cursor.iterobjects` that 
     2166    returns objects unordered. 
     2167 
     2168*   :class:`Connection` has a new method :meth:`connectstring`. 
     2169 
     2170*   A class :class:`LibraryDefinition` has been added. 
     2171 
     2172*   :meth:`CommentsDefinition.createddl` returns ``""`` instead of ``"\n"`` now 
     2173    if there are no comments. 
     2174 
     2175*   :class:`SQLObjectNotfoundError` has been renamed to 
     2176    :class:`SQLObjectNotFoundError`. 
     2177 
     2178 
     2179Changes in ll-orasql 1.0 (released 10/13/2005) 
     2180---------------------------------------------- 
     2181 
     2182*   :mod:`ll.orasql` requires version 1.0 of the core package now. 
     2183 
     2184*   A new generator method :func:`iterobjects` has been added to the 
     2185    :class:`Cursor` class. This generator returns "definition objects" for all 
     2186    the objects in a schema in topological order (i.e. if the name of an object 
     2187    (e.g. a table) is generated it will only depend on objects whose name has 
     2188    been yielded before). SQL for recreating and deleting these SQL objects can 
     2189    be generated from the definition objects. 
     2190 
     2191*   Two scripts (``oracreate.py`` and ``oradrop.py``) have been added, that 
     2192    create SQL scripts for recreating or deleting the content of an Oracle schema. 
     2193 
     2194 
     2195Changes in ll-orasql 0.7 (released 08/09/2005) 
     2196---------------------------------------------- 
     2197 
     2198*   The commands generated by :func:`iterdrop` no longer have a terminating ``;``, 
     2199    as this seems to confuse Oracle/cx_Oracle. 
     2200 
     2201 
     2202Changes in ll-orasql 0.6 (released 06/20/2005) 
     2203---------------------------------------------- 
     2204 
     2205*   Two new functions have been added: :func:`iterdrop` is a generator that 
     2206    yields information about how to clear the schema (i.e. drop all table, 
     2207    sequences, etc.). :func:`itercreate` yields information about how to recreate 
     2208    a schema. 
     2209 
     2210 
     2211Changes in ll-orasql 0.5 (released 06/07/2005) 
     2212---------------------------------------------- 
     2213 
     2214*   Date values are now supported as ``OUT`` parameters. 
     2215 
     2216 
     2217Changes in ll-orasql 0.4.1 (released 03/22/2005) 
     2218------------------------------------------------ 
     2219 
     2220*   Added a note about the package init file to the installation documentation. 
     2221 
     2222 
     2223Changes in ll-orasql 0.4 (released 01/03/2005) 
     2224---------------------------------------------- 
     2225 
     2226*   :mod:`ll.orasql` now requires ll-core. 
     2227 
     2228*   Procedures can now be called with string arguments longer that 32768 
     2229    characters. In this case the argument will be converted to a variable before 
     2230    the call. The procedure argument must be a ``CLOB`` in this case. 
     2231 
     2232*   Creating :class:`Record` instances from database data is now done by the 
     2233    class method :meth:`Record.fromdata`. This means it's now possible to use any 
     2234    other class as long as it provides this method. 
     2235 
     2236 
     2237Changes in ll-orasql 0.3 (released 12/09/2004) 
     2238---------------------------------------------- 
     2239 
     2240*   :mod:`ll.orasql` requires cx_Oracle 4.1 now. 
     2241 
     2242 
     2243Changes in ll-orasql 0.2.1 (released 09/09/2004) 
     2244------------------------------------------------ 
     2245 
     2246*   Fixed a regression bug in :meth:`Proc._calcrealargs` as cursors will now 
     2247    always return :class:`Record` objects. 
     2248 
     2249 
     2250Changes in ll-orasql 0.2 (released 09/08/2004) 
     2251---------------------------------------------- 
     2252 
     2253*   Now generating :class:`Record` object is done automatically in a subclass of 
     2254    :class:`cx_Oracle.Cursor`. So now it's possible to use :mod:`ll.orasql` as an 
     2255    extended :mod:`cx_Oracle`. 
     2256 
     2257 
     2258Changes in ll-orasql 0.1 (released 07/15/2004) 
     2259---------------------------------------------- 
     2260 
     2261*   Initial release. 
  • README.rst

    r3666 r3732  
    88'object oriented XSLT'. 
    99 
    10 XIST also includes the following modules: 
     10XIST also includes the following modules and packages: 
     11 
     12*   :mod:`ll.make` is an object oriented make replacement. Like make it allows 
     13    you to specify dependencies between files and actions to be executed 
     14    when files don't exist or are out of date with respect to one 
     15    of their sources. But unlike make you can do this in a object oriented 
     16    way and targets are not only limited to files, but you can implement 
     17    e.g. dependencies on database records. 
     18 
     19*   :mod:`ll.orasql` provides utilities for working with cx_Oracle_: 
     20 
     21    -   It allows calling functions and procedures with keyword arguments. 
     22 
     23    -   Query results will be put into Record objects, where database fields 
     24        are accessible as object attributes. 
     25 
     26    -   The :class:`Connection` class provides methods for iterating through the 
     27        database metadata. 
     28 
     29    -   Importing the modules adds support for URLs with the scheme ``oracle`` to 
     30        :mod:`ll.url`. 
     31 
     32    .. _cx_Oracle: http://cx-oracle.sourceforge.net/ 
     33 
     34*   :mod:`ll.ul4c` is compiler for a templating language with similar capabilities 
     35    to `Django's templating language`__. ``UL4`` templates are compiled to an 
     36    internal bytecode format, which makes it possible to implement template 
     37    renderers in other languages and makes the template code "secure" (i.e. 
     38    template code can't open or delete files). 
     39 
     40    __ http://www.djangoproject.com/documentation/templates/ 
     41 
     42*   :mod:`ll.url` provides classes for parsing and constructing RFC 2396 
     43    compliant URLs. 
    1144 
    1245*   :mod:`ll.astyle` can be used for colored terminal output (via ANSI escape 
     
    1851    for modifying and mixing colors. 
    1952 
    20 *   :mod:`ll.make` is an object oriented make replacement. Like make it allows 
    21     you to specify dependencies between files and actions to be executed 
    22     when files don't exist or are out of date with respect to one 
    23     of their sources. But unlike make you can do this in a object oriented 
    24     way and targets are not only limited to files, but you can implement 
    25     e.g. dependencies on database records. 
    26  
    2753*   :mod:`ll.misc` provides several small utility functions and classes. 
    2854 
     
    3056 
    3157*   :mod:`ll.daemon` can be used on UNIX to fork a daemon process. 
    32  
    33 *   :mod:`ll.url` provides classes for parsing and constructing RFC 2396 
    34     compliant URLs. 
    35  
    36 *   :mod:`ll.ul4c` is compiler for a templating language with similar capabilities 
    37     to `Django's templating language`__. ``UL4`` templates are compiled to an 
    38     internal bytecode format, which makes it possible to implement template 
    39     renderers in other languages and makes the template code "secure" (i.e. 
    40     template code can't open or delete files). 
    41  
    42     __ http://www.djangoproject.com/documentation/templates/ 
    4358 
    4459*   :mod:`ll.xml_codec` contains a complete codec for encoding and decoding XML. 
  • setup.py

    r3720 r3732  
    100100 
    101101# TOXIC 
     102Topic :: Database 
     103 
     104# orasql 
    102105Topic :: Database 
    103106""" 
     
    180183# ul4 
    181184template 
     185 
     186# orasql 
     187database 
     188Oracle 
     189cx_Oracle 
     190record 
     191procedure 
     192schema 
    182193""" 
    183194 
     
    201212args = dict( 
    202213    name="ll-xist", 
    203     version="3.6.4", 
    204     description="Extensible HTML/XML generator, cross-platform templating language and various other tools", 
     214    version="3.7", 
     215    description="Extensible HTML/XML generator, cross-platform templating language, Oracle utilities and various other tools", 
    205216    long_description=descr, 
    206217    author="Walter Doerwald", 
     
    212223    keywords=", ".join(sorted(set(k.strip() for k in KEYWORDS.strip().splitlines() if k.strip() and not k.strip().startswith("#")))), 
    213224    package_dir={"": "src"}, 
    214     packages=["ll", "ll.scripts", "ll.xist", "ll.xist.ns", "ll.xist.scripts"], 
     225    packages=["ll", "ll.scripts", "ll.xist", "ll.xist.ns", "ll.xist.scripts", "ll.orasql", "ll.orasql.scripts"], 
    215226    ext_modules=[ 
    216227        tools.Extension("ll._url", ["src/ll/_url.c"]), 
     
    228239            "doc2txt = ll.xist.scripts.doc2txt:main", 
    229240            "xml2xsc = ll.xist.scripts.xml2xsc:main", 
     241            "oracreate = ll.orasql.scripts.oracreate:main [oracle]", 
     242            "oradrop = ll.orasql.scripts.oradrop:main [oracle]", 
     243            "oradelete = ll.orasql.scripts.oradelete:main [oracle]", 
     244            "oradiff = ll.orasql.scripts.oradiff:main [oracle]", 
     245            "oramerge = ll.orasql.scripts.oramerge:main [oracle]", 
     246            "oragrant = ll.orasql.scripts.oragrant:main [oracle]", 
     247            "orafind = ll.orasql.scripts.orafind:main [oracle]", 
    230248        ] 
    231249    ), 
     
    237255        "scripts/doc2txt.py", 
    238256        "scripts/xml2xsc.py", 
     257        "scripts/oracreate.py", 
     258        "scripts/oradrop.py", 
     259        "scripts/oradelete.py", 
     260        "scripts/oradiff.py", 
     261        "scripts/oramerge.py", 
     262        "scripts/oragrant.py", 
     263        "scripts/orafind.py", 
    239264    ], 
    240265    install_requires=[ 
    241266        "cssutils == 0.9.5.1", 
    242267    ], 
     268    extras_require = { 
     269        "oracle":  ["cx_Oracle >= 5.0.1"], 
     270    }, 
    243271    namespace_packages=["ll"], 
    244272    zip_safe=False, 
     273    dependency_links=[ 
     274        "http://sourceforge.net/project/showfiles.php?group_id=84168", # cx_Oracle 
     275    ], 
    245276) 
    246277 
  • src/ll/make.py

    r3730 r3732  
    2929this:: 
    3030 
    31     from ll import make, url 
     31    from ll import make 
    3232 
    3333    class MyProject(make.Project): 
    3434        def create(self): 
    3535            make.Project.create(self) 
    36             source = self.add(make.FileAction(url.File("foo.txt"))) 
    37             target = self.add( 
    38                 source / 
    39                 make.DecodeAction("iso-8859-1") / 
    40                 make.EncodeAction("utf-8") / 
    41                 make.FileAction(url.File("bar.txt")) 
    42             ) 
     36            source = self.add(make.FileAction("foo.txt")) 
     37            temp = make.CallAttrAction(source, "decode", "iso-8859-1") 
     38            temp = make.CallAttrAction(temp, "encode", "utf-8") 
     39            target = self.add(make.FileAction("bar.txt", temp)) 
    4340            self.writecreatedone() 
    4441 
     
    298295    """ 
    299296    An :class:`Action` is responsible for transforming input data into output 
    300     data. It may have no, one or many input actions. It fetches, combines and 
    301     transforms the output data of those actions and returns its own output data. 
     297    data. It may have no, one or many inputs which themselves may be other actions. 
     298    It fetches, combines and transforms the output data of those actions and 
     299    returns its own output data. 
    302300    """ 
    303301 
     
    318316        :class:`datetime.datetime` object in UTC). If the data hasn't changed 
    319317        since :var:`since` the special object :const:`nodata` must be returned. 
    320          
     318 
    321319        In both cases the action must make sure that the data is internally 
    322320        consistent, i.e. if the input data is the output data of other actions 
     
    360358        :class:`ModuleAction` for the filename. 
    361359        """ 
    362         return getattr(self, "key", None) 
     360        return self.key 
    363361 
    364362    def getargs(self): 
     
    472470 
    473471 
    474 class PipeAction(Action): 
    475     """ 
    476     A :class:`PipeAction` depends on exactly one input action and transforms 
     472class TransformAction(Action): 
     473    """ 
     474    A :class:`TransformAction` depends on exactly one input action and transforms 
    477475    the input data into output data. 
    478476    """ 
     
    491489 
    492490 
    493 class CollectAction(PipeAction): 
    494     """ 
    495     A :class:`CollectAction` is a :class:`PipeAction` that simply outputs its 
     491class CollectAction(TransformAction): 
     492    """ 
     493    A :class:`CollectAction` is a :class:`TransformAction` that simply outputs its 
    496494    input data unmodified, but updates a number of other actions in the process. 
    497495    """ 
    498496    def __init__(self, input=None, *otherinputs): 
    499         PipeAction.__init__(self, input) 
     497        TransformAction.__init__(self, input) 
    500498        self.otherinputs = list(otherinputs) 
    501499 
     
    509507 
    510508    def __iter__(self): 
    511         for input in PipeAction.__iter__(self): 
     509        for input in TransformAction.__iter__(self): 
    512510            yield input 
    513511        for input in self.otherinputs: 
     
    590588 
    591589 
    592 class FileAction(PipeAction): 
     590class FileAction(TransformAction): 
    593591    """ 
    594592    A :class:`FileAction` is used for reading and writing files (and other 
     
    602600        data written to the file (or the action producing the data). 
    603601        """ 
    604         PipeAction.__init__(self, input) 
    605         self.key = key 
     602        TransformAction.__init__(self, input) 
     603        self.key = url.URL(key) 
    606604        self.buildno = None 
    607605 
     
    664662 
    665663 
    666 class UnpickleAction(PipeAction): 
    667     """ 
    668     This action unpickles a string. 
    669     """ 
    670     def execute(self, project, data): 
    671         project.writestep(self, "Unpickling ", len(data), " bytes") 
    672         return cPickle.loads(data) 
    673  
    674  
    675 class PickleAction(PipeAction): 
    676     """ 
    677     This action pickles the input data into a string. 
    678     """ 
    679     def __init__(self, input=None, protocol=0): 
    680         """ 
    681         Create a new :class:`PickleAction` instance. :var:`protocol` is used as 
    682         the pickle protocol. 
    683         """ 
    684         PipeAction.__init__(self, input) 
    685         self.protocol = protocol 
    686  
    687     def __iter__(self): 
    688         for input in PipeAction.__iter__(self): 
    689             yield input 
    690         yield self.protocol 
    691  
    692     def getkwargs(self): 
    693         return dict(data=self.input, protocol=self.protocol) 
    694  
    695     def execute(self, data, protocol): 
    696         project.writestep(self, "Pickling ", len(data), " bytes with protocol %r" % protocol) 
    697         return cPickle.dumps(data, protocol) 
    698         return data 
    699  
    700  
    701 class JoinAction(Action): 
    702     """ 
    703     This action joins the input of all its input actions into one string. 
    704     """ 
    705     def __init__(self, *inputs): 
    706         Action.__init__(self) 
    707         self.inputs = list(inputs) 
    708  
    709     def addinputs(self, *inputs): 
    710         """ 
    711         Register all actions in :var:`inputs` as input actions, whose data gets 
    712         joined (in the order in which they have been passed to :meth:`addinputs`). 
    713         """ 
    714         self.inputs.extend(inputs) 
    715         return self 
    716  
    717     def __iter__(self): 
    718         return iter(self.inputs) 
    719  
    720     def getargs(self): 
    721         return (self.inputs,) 
    722  
    723     def execute(self, project, inputs): 
    724         project.writestep(self, "Joining data from ", len(inputs), " inputs") 
    725         return "".join(inputs) 
    726  
    727  
    728 class MkDirAction(PipeAction): 
     664class MkDirAction(TransformAction): 
    729665    """ 
    730666    This action creates the a directory (passing through its input data). 
     
    737673        directory. 
    738674        """ 
    739         PipeAction.__init__(self) 
     675        TransformAction.__init__(self) 
    740676        self.key = key 
    741677        self.mode = mode 
     
    753689 
    754690 
    755 class CacheAction(PipeAction): 
    756     """ 
    757     A :class:`CacheAction` is a :class:`PipeAction` that passes through its 
     691class PipeAction(TransformAction): 
     692    """ 
     693    This action pipes the input through an external shell command. 
     694    """ 
     695 
     696    def __init__(self, input, command): 
     697        """ 
     698        Create a :class:`PipeAction` instance. :var:`command` is the shell command 
     699        to be executed (which must read it's input from sdtin and write its output 
     700        to stdout). 
     701        """ 
     702        TransformAction.__init__(self, input) 
     703        self.command = command 
     704 
     705    def getkwargs(self): 
     706        return dict(data=self.input, command=self.command) 
     707 
     708    def execute(self, project, data, command): 
     709        project.writestep(self, "Calling command ", command) 
     710        (stdin, stdout) = os.popen2(command) 
     711 
     712        stdin.write(data) 
     713        stdin.close() 
     714        output = stdout.read() 
     715        stdout.close() 
     716        return output 
     717 
     718    def __repr__(self): 
     719        return "<%s.%s object with command=%r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.command, id(self)) 
     720 
     721 
     722class CacheAction(TransformAction): 
     723    """ 
     724    A :class:`CacheAction` is a :class:`TransformAction` that passes through its 
    758725    input data, but caches it, so that it can be reused during the same build 
    759726    round. 
    760727    """ 
    761728    def __init__(self, input=None): 
    762         PipeAction.__init__(self, input) 
     729        TransformAction.__init__(self, input) 
    763730        self.since = bigcrunch 
    764731        self.data = nodata 
     
    778745 
    779746 
    780 class GetAttrAction(PipeAction): 
     747class GetAttrAction(TransformAction): 
    781748    """ 
    782749    This action gets an attribute from its input object. 
     
    784751 
    785752    def __init__(self, input=None, attrname=None): 
    786         PipeAction.__init__(self, input) 
     753        TransformAction.__init__(self, input) 
    787754        self.attrname = attrname 
    788755 
    789756    def __iter__(self): 
    790         for input in PipeAction.__iter__(self): 
     757        for input in TransformAction.__iter__(self): 
    791758            yield input 
    792759        yield self.attrname 
     
    846813 
    847814 
    848 class XISTParseAction(PipeAction): 
     815class XISTParseAction(TransformAction): 
    849816    """ 
    850817    This action parses the input data (a string) into an XIST node. 
     
    859826        base URL used for parsing. 
    860827        """ 
    861         PipeAction.__init__(self, input) 
     828        TransformAction.__init__(self, input) 
    862829        if builder is None: 
    863830            from ll.xist import parsers 
     
    868835 
    869836    def __iter__(self): 
    870         for input in PipeAction.__iter__(self): 
     837        for input in TransformAction.__iter__(self): 
    871838            yield input 
    872839        yield self.builder 
     
    889856 
    890857 
    891 class XISTConvertAction(PipeAction): 
     858class XISTConvertAction(TransformAction): 
    892859    """ 
    893860    This action transform an XIST node. 
     
    905872        to the project. 
    906873        """ 
    907         PipeAction.__init__(self, input) 
     874        TransformAction.__init__(self, input) 
    908875        self.mode = mode 
    909876        self.target = target 
     
    913880 
    914881    def __iter__(self): 
    915         for input in PipeAction.__iter__(self): 
     882        for input in TransformAction.__iter__(self): 
    916883            yield input 
    917884        yield self.mode 
     
    936903 
    937904 
    938 class XISTBytesAction(PipeAction): 
    939     """ 
    940     This action publishes an XIST node as a byte string. 
    941     """ 
    942  
    943     def __init__(self, input=None, publisher=None, base=None): 
    944         """ 
    945         Create an :class:`XISTBytesAction` object. :var:`publisher` must be an 
    946         instance of :class:`ll.xist.publishers.Publisher`. If :var:`publisher` is 
    947         :const:`None` a publisher will be created for you. :var:`base` will be 
    948         the base URL used for publishing. 
    949         """ 
    950         PipeAction.__init__(self, input) 
    951         self.publisher = publisher 
    952         self.base = base 
    953  
    954     def __iter__(self): 
    955         for input in PipeAction.__iter__(self): 
    956             yield input 
    957         yield self.publisher 
    958         yield self.base 
    959  
    960     def getkwargs(self): 
    961         return dict(data=self.input, publisher=self.publisher, base=self.base) 
    962  
    963     def execute(self, project, data, publisher, base): 
    964         project.writestep(self, "Publishing XIST node as byte string with base ", base) 
    965         return data.bytes(publisher=publisher, base=base) 
    966  
    967  
    968 class XISTStringAction(PipeAction): 
    969     """ 
    970     This action publishes an XIST node as a unicode string. 
    971     """ 
    972  
    973     def __init__(self, input=None, publisher=None, base=None): 
    974         """ 
    975         Create an :class:`XISTStringhAction` object. :var:`publisher` must be an 
    976         instance of :class:`ll.xist.publishers.Publisher`. If :var:`publisher` is 
    977         :const:`None` a publisher will be created for you. :var:`base` will be 
    978         the base URL used for publishing. 
    979         """ 
    980         PipeAction.__init__(self, input) 
    981         self.publisher = publisher 
    982         self.base = base 
    983  
    984     def __iter__(self): 
    985         for input in PipeAction.__iter__(self): 
    986             yield input 
    987         yield self.publisher 
    988         yield self.base 
    989  
    990     def getkwargs(self): 
    991         return dict(data=self.input, publisher=self.publisher, base=self.base) 
    992  
    993     def execute(self, project, data, publisher, base): 
    994         project.writestep(self, "Publishing XIST node as unicode string with base ", base) 
    995         return data.string(publisher=publisher, base=base) 
    996  
    997  
    998 class XISTTextAction(PipeAction): 
     905class XISTTextAction(TransformAction): 
    999906    """ 
    1000907    This action creates a plain text version of an HTML XIST node. 
    1001908    """ 
    1002909    def __init__(self, input=None, encoding="iso-8859-1", width=72): 
    1003         PipeAction.__init__(self, input) 
     910        TransformAction.__init__(self, input) 
    1004911        self.encoding = encoding 
    1005912        self.width = width 
    1006913 
    1007914    def __iter__(self): 
    1008         for input in PipeAction.__iter__(self): 
     915        for input in TransformAction.__iter__(self): 
    1009916            yield input 
    1010917        yield self.encoding 
     
    1020927 
    1021928 
    1022 class FOPAction(PipeAction): 
     929class FOPAction(TransformAction): 
    1023930    """ 
    1024931    This action transforms an XML string (containing XSL-FO) into PDF. For it 
     
    1045952            os.remove(outname) 
    1046953        return data 
    1047  
    1048  
    1049 class DecodeAction(PipeAction): 
    1050     """ 
    1051     This action decodes an input :class:`str` object into an output 
    1052     :class:`unicode` object. 
    1053     """ 
    1054  
    1055     def __init__(self, input=None, encoding=None): 
    1056         """ 
    1057         Create a :class:`DecodeAction` object with :var:`encoding` as the name of 
    1058         the encoding. If :var:`encoding` is :const:`None` the system default 
    1059         encoding will be used. 
    1060         """ 
    1061         PipeAction.__init__(self, input) 
    1062         if encoding is None: 
    1063             encoding = sys.getdefaultencoding() 
    1064         self.encoding = encoding 
    1065  
    1066     def __iter__(self): 
    1067         for input in PipeAction.__iter__(self): 
    1068             yield input 
    1069         yield self.encoding 
    1070  
    1071     def getkwargs(self): 
    1072         return dict(data=self.input, encoding=self.encoding) 
    1073  
    1074     def execute(self, project, data, encoding): 
    1075         project.writestep(self, "Decoding ", len(data), " bytes with encoding ", encoding) 
    1076         return data.decode(encoding) 
    1077  
    1078  
    1079 class EncodeAction(PipeAction): 
    1080     """ 
    1081     This action encodes an input :class:`unicode` object into an output 
    1082     :class:`str` object. 
    1083     """ 
    1084  
    1085     def __init__(self, input=None, encoding=None): 
    1086         """ 
    1087         Create an :class:`EncodeAction` object with :var:`encoding` as the name 
    1088         of the encoding. If :var:`encoding` is :const:`None` the system default 
    1089         encoding will be used. 
    1090         """ 
    1091         PipeAction.__init__(self, input) 
    1092         if encoding is None: 
    1093             encoding = sys.getdefaultencoding() 
    1094         self.encoding = encoding 
    1095  
    1096     def __iter__(self): 
    1097         for input in PipeAction.__iter__(self): 
    1098             yield input 
    1099         yield self.encoding 
    1100  
    1101     def getkwargs(self): 
    1102         return dict(data=self.input, encoding=self.encoding) 
    1103  
    1104     def execute(self, project, data, encoding): 
    1105         project.writestep(self, "Encoding ", len(data), " characters with encoding ", encoding) 
    1106         return data.encode(encoding) 
    1107  
    1108  
    1109 class JSONDecodeAction(PipeAction): 
    1110     """ 
    1111     This action decodes an input :class:`str` object in JSON format into an 
    1112     output :class:`unicode` object. 
    1113     """ 
    1114  
    1115     def __init__(self, input=None): 
    1116         """ 
    1117         Create a :class:`JSONDecodeAction` object. 
    1118         """ 
    1119         PipeAction.__init__(self, input) 
    1120  
    1121     def execute(self, project, data, encoding): 
    1122         project.writestep(self, "Decoding ", len(data), " bytes with encoding ", encoding) 
    1123         return data.decode(encoding) 
    1124  
    1125  
    1126 class JSONEncodeAction(PipeAction): 
    1127     """ 
    1128     This action encodes an input :class:`unicode` object into an output 
    1129     :class:`str` object. 
    1130     """ 
    1131  
    1132     def __init__(self, input=None, encoding=None): 
    1133         """ 
    1134         Create an :class:`EncodeAction` object with :var:`encoding` as the name 
    1135         of the encoding. If :var:`encoding` is :const:`None` the system default 
    1136         encoding will be used. 
    1137         """ 
    1138         PipeAction.__init__(self, input) 
    1139         if encoding is None: 
    1140             encoding = sys.getdefaultencoding() 
    1141         self.encoding = encoding 
    1142  
    1143     def __iter__(self): 
    1144         for input in PipeAction.__iter__(self): 
    1145             yield input 
    1146         yield self.encoding 
    1147  
    1148     def getkwargs(self): 
    1149         return dict(data=self.input, encoding=self.encoding) 
    1150  
    1151     def execute(self, project, data, encoding): 
    1152         project.writestep(self, "Encoding ", len(data), " characters with encoding ", encoding) 
    1153         return data.encode(encoding) 
    1154  
    1155  
    1156 class EvalAction(PipeAction): 
    1157     """ 
    1158     This action evaluates an input string and returns the resulting output 
    1159     object. 
    1160     """ 
    1161  
    1162     def execute(self, project, data): 
    1163         project.writestep(self, "Evaluating input") 
    1164         return eval(input) 
    1165  
    1166  
    1167 class GZipAction(PipeAction): 
    1168     """ 
    1169     This action compresses the input string via gzip and returns the resulting 
    1170     compressed output object. 
    1171     """ 
    1172     def __init__(self, input=None, compresslevel=9): 
    1173         PipeAction.__init__(self, input) 
    1174         self.compresslevel = compresslevel 
    1175  
    1176     def __iter__(self): 
    1177         for input in PipeAction.__iter__(self): 
    1178             yield input 
    1179         yield self.compresslevel 
    1180  
    1181     def getkwargs(self): 
    1182         return dict(data=self.input, compresslevel=self.compresslevel) 
    1183  
    1184     def execute(self, project, data, compresslevel): 
    1185         project.writestep(self, "Compressing ", len(data), " bytes with level " % compresslevel) 
    1186         from ll import misc 
    1187         return misc.gzip(data, compresslevel) 
    1188  
    1189  
    1190 class GUnzipAction(PipeAction): 
    1191     """ 
    1192     This action uncompresses the input string via gzip and returns the resulting 
    1193     uncompressed output object. 
    1194     """ 
    1195     def execute(self, project, data): 
    1196         project.writestep(self, "Uncompressing ", len(data), " bytes") 
    1197         return misc.gunzip(data) 
    1198  
    1199  
    1200 class JavascriptMinifyAction(PipeAction): 
    1201     """ 
    1202     This action minimizes Javascript code. 
    1203     """ 
    1204     def execute(self, project, data): 
    1205         project.writestep(self, "Minimizing ", len(data), " ", ("bytes" if isinstance(data, str) else "characters"), " of Javascript code") 
    1206         from ll import misc 
    1207         return misc.jsmin(data) 
    1208  
    1209  
    1210 class CallFuncAction(Action): 
    1211     """ 
    1212     This action calls a function with a number of arguments. Both positional and 
    1213     keyword arguments are supported and the function and the arguments can be 
    1214     static objects or actions. 
    1215     """ 
    1216     def __init__(self, func, *args, **kwargs): 
    1217         Action.__init__(self) 
    1218         self.func = func 
    1219         self.args = args 
    1220         self.kwargs = kwargs 
    1221  
    1222     def __iter__(self): 
    1223         yield self.func 
    1224         for input in self.args: 
    1225             yield input 
    1226         for input in self.kwargs.itervalues(): 
    1227             yield input 
    1228  
    1229     def getargs(self): 
    1230         return (self.func,) + self.args 
    1231  
    1232     def getkwargs(self): 
    1233         return self.kwargs 
    1234  
    1235     def execute(self, project, func, *args, **kwargs): 
    1236         project.writestep(self, "Calling function %r" % func) 
    1237         return func(*args **kwargs) 
    1238954 
    1239955 
     
    13151031 
    13161032 
    1317 class TOXICAction(PipeAction): 
    1318     """ 
    1319     This action transforms a TOXIC template code into an Oracle or SQL Server 
    1320     function or procedure body via the TOXIC compiler (:mod:`ll.toxicc`). 
    1321     """ 
    1322  
    1323     def __init__(self, input=None, mode="oracle"): 
    1324         PipeAction.__init__(self, input) 
    1325         self.mode = mode 
    1326  
    1327     def getkwargs(self): 
    1328         return dict(data=self.input, mode=self.mode) 
    1329  
    1330     def execute(self, project, data, mode): 
    1331         project.writestep(self, "Compiling TOXIC template with mode %r" % mode) 
    1332         from ll import toxicc 
    1333         return toxicc.compile(data, mode=mode) 
    1334  
    1335  
    1336 class TOXICPrettifyAction(PipeAction): 
    1337     """ 
    1338     This action tries to fix the indentation of a SQL snippet via the 
    1339     :func:`ll.toxicc.prettify` function. 
    1340     """ 
    1341  
    1342     def __init__(self, input=None, mode="oracle"): 
    1343         PipeAction.__init__(self, input) 
    1344         self.mode = mode 
    1345  
    1346     def __iter__(self): 
    1347         for input in PipeAction.__iter__(self): 
    1348             yield input 
    1349         yield self.mode 
    1350  
    1351     def getkwargs(self): 
    1352         return dict(data=self.input, mode=self.mode) 
    1353  
    1354     def execute(self, project, data, mode): 
    1355         project.writestep(self, "Prettifying SQL code with mode %r" % mode) 
    1356         from ll import toxicc 
    1357         return toxicc.prettify(data, mode=mode) 
    1358  
    1359  
    1360 class SplatAction(PipeAction): 
    1361     """ 
    1362     This action transforms an input string by replacing regular expressions. 
    1363     """ 
    1364  
    1365     def __init__(self, input=None, patterns=[]): 
    1366         """ 
    1367         Create a new :class:`SplatAction` object. :var:`patterns` are pattern 
    1368         pairs. Each first entry will be replaced by the corresponding second 
    1369         entry. 
    1370         """ 
    1371         PipeAction.__init__(self, input) 
    1372         self.patterns = patterns 
    1373  
    1374     def getkwargs(self): 
    1375         return dict(data=self.input, patterns=self.patterns) 
    1376  
    1377     def execute(self, project, data, patterns): 
    1378         for (search, replace) in patterns: 
    1379             project.writestep(self, "Replacing ", search, " with ", replace) 
    1380             data = re.sub(search, replace, data) 
    1381         return data 
    1382  
    1383  
    1384 class UL4CompileAction(PipeAction): 
    1385     """ 
    1386     This action compiles a UL4 template into a :class:`ll.ul4c.Template` object. 
    1387     """ 
    1388  
    1389     def execute(self, project, data): 
    1390         project.writestep(self, "Compiling ", len(data), (" bytes" if isinstance(data, str) else " characters"), " to UL4 template") 
    1391         from ll import ul4c 
    1392         return ul4c.compile(data) 
    1393  
    1394  
    1395 class UL4RenderAction(PipeAction): 
    1396     """ 
    1397     This action renders a UL4 template to a string. 
    1398     """ 
    1399     def __init__(self, input=None, **vars): 
    1400         PipeAction.__init__(self, input) 
    1401         self.vars = vars 
    1402  
    1403     def __iter__(self): 
    1404         for input in PipeAction.__iter__(self): 
    1405             yield input 
    1406         for input in self.vars.itervalues(): 
    1407             yield input 
    1408  
    1409     def getargs(self): 
    1410         return (self.input,) 
    1411  
    1412     def getkwargs(self): 
    1413         return self.vars 
    1414  
    1415     def execute(self, project, data, **vars): 
    1416         project.writestep(self, "Rendering UL4 template with ", len(self.opcodes), " opcodes") 
    1417         return data.renders(**vars) 
    1418  
    1419  
    1420 class UL4DumpAction(PipeAction): 
    1421     """ 
    1422     This action dumps an :class:`ll.ul4c.Template` object into a string. 
    1423     """ 
    1424  
    1425     def execute(self, project, data): 
    1426         project.writestep(self, "Dumping UL4 template with ", len(data.opcodes), " opcodes") 
    1427         return data.dumps() 
    1428  
    1429  
    1430 class UL4LoadAction(PipeAction): 
    1431     """ 
    1432     This action loads a :class:`ll.ul4c.Template` object from a string. 
    1433     """ 
    1434  
    1435     def execute(self, project, data): 
    1436         project.writestep(self, "Loading UL4 template from ", len(data), (" bytes" if isinstance(data, str) else " characters")) 
    1437         from ll import ul4c 
    1438         return ul4c.loads(data) 
    1439  
    1440  
    1441 class CommandAction(PipeAction): 
     1033class CommandAction(TransformAction): 
    14421034    """ 
    14431035    This action executes a system command (via :func:`os.system`) and passes 
     
    14501042        that will executed when :meth:`execute` is called. 
    14511043        """ 
    1452         PipeAction.__init__(self, input) 
     1044        TransformAction.__init__(self, input) 
    14531045        self.command = command 
    14541046 
     
    14611053 
    14621054 
    1463 class ModeAction(PipeAction): 
     1055class ModeAction(TransformAction): 
    14641056    """ 
    14651057    :class:`ModeAction` changes file permissions and passes through the input data. 
     
    14711063        :const:`0644`) will be use as the permission bit pattern. 
    14721064        """ 
    1473         PipeAction.__init__(self, input) 
     1065        TransformAction.__init__(self, input) 
    14741066        self.mode = mode 
    14751067 
    14761068    def __iter__(self): 
    1477         for input in PipeAction.__iter__(self): 
     1069        for input in TransformAction.__iter__(self): 
    14781070            yield input 
    14791071        yield self.mode 
     
    14921084 
    14931085 
    1494 class OwnerAction(PipeAction): 
     1086class OwnerAction(TransformAction): 
    14951087    """ 
    14961088    :class:`OwnerAction` changes the user and/or group ownership of a file and 
     
    15041096        no user ownership will be changed. The same applies to :var:`group`. 
    15051097        """ 
    1506         PipeAction.__init__(self, input) 
     1098        TransformAction.__init__(self, input) 
    15071099        self.id = id 
    15081100        self.user = user 
     
    15101102 
    15111103    def __iter__(self): 
    1512         for input in PipeAction.__iter__(self): 
     1104        for input in TransformAction.__iter__(self): 
    15131105            yield input 
    15141106        yield self.user 
     
    15281120 
    15291121 
    1530 class ModuleAction(PipeAction): 
     1122class ModuleAction(TransformAction): 
    15311123    """ 
    15321124    This action will turn the input string into a Python module. 
     
    15391131        that creates the source file). 
    15401132        """ 
    1541         PipeAction.__init__(self, input) 
     1133        TransformAction.__init__(self, input) 
    15421134        self.inputs = [] 
    15431135        self.changed = bigbang 
     
    15501142        These actions must be :class:`ModuleAction` objects too. 
    15511143 
    1552         Normally it isn't neccessary to call the method explicitly. Instead 
     1144        Normally it isn't neccessary to call the method directly. Instead 
    15531145        fetch the required module inside your module like this:: 
    15541146 
     
    15581150 
    15591151        This will record your module as depending on :mod:`mymodule`, so if 
    1560         :mod:`mymodule` changes your module will be reloaded too. For this to 
     1152        :mod:`mymodule` changes, your module will be reloaded too. For this to 
    15611153        work you need to have an :class:`ModuleAction` added to the project with 
    15621154        the key ``"mymodule.py"``. 
     
    15661158 
    15671159    def __iter__(self): 
    1568         for input in PipeAction.__iter__(self): 
     1160        for input in TransformAction.__iter__(self): 
    15691161            yield input 
    15701162        for input in self.inputs: 
     
    16421234 
    16431235 
    1644 class ModuleName(str): 
    1645     """ 
    1646     :class:`ModuleName` objects are automatically created by :class:`ImportAction` 
    1647     as keys to be able to distinguish those keys from the keys for 
    1648     :class:`PhonyAction`\s (which are normally :class:`str` objects). 
    1649     """ 
    1650     def __eq__(self, other): 
    1651         return self.__class__ is other.__class__ and str.__eq__(self, other) 
    1652  
    1653     def __ne__(self, other): 
    1654         return not self == other 
    1655  
    1656     def __repr__(self): 
    1657         return "%s.%s(%s)" % (self.__class__.__module__, self.__class__.__name__, str.__repr__(self)) 
    1658  
    1659  
    1660 class ImportAction(Action): 
    1661     """ 
    1662     This action imports a module specified by module name. 
    1663     """ 
    1664     def __init__(self, modulename): 
    1665         """ 
    1666         Create a :class:`ImportAction` object. :var:`modulename` must be the 
    1667         module name as a :class:`str`. 
    1668         """ 
    1669         Action.__init__(self) 
    1670         self.key = ModuleName(modulename) 
    1671         self.changed = bigbang 
    1672         self.module = None 
    1673  
    1674     def __iter__(self): 
    1675         yield self.key 
    1676  
    1677     @report 
    1678     def get(self, project, since): 
    1679         if self.module is None: 
    1680             module = __import__(self.key) 
    1681             for subname in self.key.split(".")[1:]: 
    1682                 module = getattr(module, subname) 
    1683             self.changed = filechanged(url.File(module.__file__)) 
    1684             self.module = module 
    1685             args = ["Imported module %s" % self.key] 
    1686             if project.showtimestamps: 
    1687                 args.append(" (changed ") 
    1688                 args.append(project.strdatetime(self.changed)) 
    1689                 args.append(")") 
    1690             project.writestep(self, *args) 
    1691         if self.changed > since: 
    1692             return self.module 
    1693         return nodata 
    1694  
    1695     def __repr__(self): 
    1696         return "ImportAction(%r)" % str(self.key) 
    1697  
    1698  
    16991236class AlwaysAction(Action): 
    17001237    """ 
     
    17261263        return nodata 
    17271264neveraction = NeverAction() # this action can be reused as it has no inputs 
    1728  
    1729  
    1730 ### 
    1731 ### Classes for target keys (apart from strings for :const:`PhonyAction` objects and URLs for :class:`FileAction` objects) 
    1732 ### 
    1733  
    1734 class DBKey(object): 
    1735     """ 
    1736     This class provides a unique identifier for database content. This can be 
    1737     used as an key for :class:`FileAction` objects and other actions that are 
    1738     not files, but database records, function, procedures etc. 
    1739     """ 
    1740     name = None 
    1741  
    1742     def __init__(self, connection, type, name, key=None): 
    1743         """ 
    1744         Create a new :class:`DBKey` instance. Arguments are: 
    1745  
    1746         :var:`connection` : string 
    1747             A string that specifies the connection to the database. E.g. 
    1748             ``"user/pwd@db.example.com"`` for Oracle. 
    1749  
    1750         :var:`type` : string 
    1751             The type of the object. Values may be ``"table"``, ``"view"``, 
    1752             ``"function"``, ``"procedure"`` etc. 
    1753  
    1754         :var:`name` : string 
    1755             The name of the object 
    1756  
    1757         :var:`key` : any object 
    1758             If :var:`name` refers to a table, :var:`key` can be used to specify 
    1759             a row in this table. 
    1760         """ 
    1761         self.connection = connection 
    1762         self.type = type.lower() 
    1763         self.name = name.lower() 
    1764         self.key = key 
    1765  
    1766     def __eq__(self, other): 
    1767         res = self.__class__ == other.__class__ 
    1768         if not res: 
    1769             res = self.connection==other.connection and self.type==other.type and self.name==other.name and self.key==other.key 
    1770         return res 
    1771  
    1772     def __hash__(self): 
    1773         return hash(self.connection) ^ hash(self.type) ^ hash(self.name) ^ hash(self.key) 
    1774  
    1775     def __repr__(self): 
    1776         args = [] 
    1777         for attrname in ("connection", "type", "name", "key"): 
    1778             attrvalue = getattr(self, attrname) 
    1779             if attrvalue is not None: 
    1780                 args.append("%s=%r" % (attrname, attrvalue)) 
    1781         return "%s(%s)" % (self.__class__.__name__, ", ".join(args)) 
    1782  
    1783     def __str__(self): 
    1784         s = "%s:%s|%s:%s" % (self.__class__.name, self.connection, self.type, self.name) 
    1785         if self.key is not None: 
    1786             s += "|%s" % (self.key,) 
    1787         return s 
    1788  
    1789  
    1790 class OracleConnection(url.Connection): 
    1791     def __init__(self, context, connection): 
    1792         self.context = context 
    1793         import cx_Oracle 
    1794         self.cursor = cx_Oracle.connect(connection).cursor() 
    1795  
    1796     def open(self, url, mode="rb"): 
    1797         return OracleResource(self, url, mode) 
    1798  
    1799     def mimetype(self, url): 
    1800         return "text/x-oracle-%s" % url.type 
    1801  
    1802     def cdate(self, url): 
    1803         # FIXME: This isn't the correct time zone, but Oracle doesn't provide anything better 
    1804         self.cursor.execute("select created, to_number(to_char(systimestamp, 'TZH')), to_number(to_char(systimestamp, 'TZM')) from user_objects where lower(object_type)=:type and lower(object_name)=:name", type=url.type, name=url.name) 
    1805         row = self.cursor.fetchone() 
    1806         if row is None: 
    1807             raise IOError(errno.ENOENT, "no such %s: %s" % (url.type, url.name)) 
    1808         return row[0]-datetime.timedelta(seconds=60*(row[1]*60+row[2])) 
    1809  
    1810     def mdate(self, url): 
    1811         # FIXME: This isn't the correct time zone, but Oracle doesn't provide anything better 
    1812         self.cursor.execute("select last_ddl_time, to_number(to_char(systimestamp, 'TZH')), to_number(to_char(systimestamp, 'TZM')) from user_objects where lower(object_type)=:type and lower(object_name)=:name", type=url.type, name=url.name) 
    1813         row = self.cursor.fetchone() 
    1814         if row is None: 
    1815             raise IOError(errno.ENOENT, "no such %s: %s" % (url.type, url.name)) 
    1816         return row[0]-datetime.timedelta(seconds=60*(row[1]*60+row[2])) 
    1817  
    1818     def __repr__(self): 
    1819         return "<%s.%s to %r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.cursor.connection.connectstring(), id(self)) 
    1820  
    1821  
    1822 class OracleKey(DBKey): 
    1823     name = "oracle" 
    1824  
    1825     def connect(self, context=None): 
    1826         context = url.getcontext(context) 
    1827         if context is url.defaultcontext: 
    1828             raise ValueError("oracle URLs need a custom context") 
    1829  
    1830         # Use one OracleConnection for each connectstring 
    1831         try: 
    1832             connections = context.schemes["oracle"] 
    1833         except KeyError: 
    1834             connections = context.schemes["oracle"] = {} 
    1835         try: 
    1836             connection = connections[self.connection] 
    1837         except KeyError: 
    1838             connection = connections[self.connection] = OracleConnection(context, self.connection) 
    1839         return connection 
    1840  
    1841     def __getattr__(self, name): 
    1842         def realattr(*args, **kwargs): 
    1843             try: 
    1844                 context = kwargs["context"] 
    1845             except KeyError: 
    1846                 context = None 
    1847             else: 
    1848                 kwargs = kwargs.copy() 
    1849                 del kwargs["context"] 
    1850             connection = self.connect(context=context) 
    1851             return getattr(connection, name)(self, *args, **kwargs) 
    1852         return realattr 
    1853  
    1854     def mimetype(self): 
    1855         return "text/x-oracle-%s" % self.type 
    1856  
    1857     def open(self, mode="rb", context=None, *args, **kwargs): 
    1858         connection = self.connect(context=context) 
    1859         return connection.open(self, mode, *args, **kwargs) 
    1860  
    1861  
    1862 class OracleResource(url.Resource): 
    1863     """ 
    1864     An :class:`OracleResource` wraps a function or procedure in an Oracle 
    1865     database in a file-like API. 
    1866     """ 
    1867     def __init__(self, connection, url, mode="rb"): 
    1868         self.connection = connection 
    1869         self.url = url 
    1870         self.mode = mode 
    1871         self.closed = False 
    1872         self.name = str(self.url) 
    1873  
    1874         if self.url.type not in ("function", "procedure"): 
    1875             raise ValueError("don't know how to handle %r" % self.url) 
    1876         if "w" in self.mode: 
    1877             self.stream = cStringIO.StringIO() 
    1878             self.stream.write("create or replace %s %s\n" % (self.url.type, self.url.name)) 
    1879         else: 
    1880             cursor = self.connection.cursor 
    1881             cursor.execute("select text from user_source where lower(name)=lower(:name) and type='%s' order by line" % self.url.type.upper(), name=self.url.name) 
    1882             code = "\n".join((row[0] or "").rstrip() for row in cursor) 
    1883             if not code: 
    1884                 raise IOError(errno.ENOENT, "no such %s: %s" % (self.url.type, self.url.name)) 
    1885             # drop type 
    1886             code = code.split(None, 1)[1] 
    1887             # skip name 
    1888             for (i, c) in enumerate(code): 
    1889                 if not c.isalpha() and c != "_": 
    1890                     break 
    1891             code = code[i:] 
    1892             self.stream = cStringIO.StringIO(code) 
    1893  
    1894     def __getattr__(self, name): 
    1895         if self.closed: 
    1896             raise ValueError("I/O operation on closed file") 
    1897         return getattr(self.stream, name) 
    1898  
    1899     def mimetype(self): 
    1900         return "text/x-oracle-%s" % self.url.type 
    1901  
    1902     def cdate(self): 
    1903         return self.connection.cdate(self.url) 
    1904  
    1905     def mdate(self): 
    1906         return self.connection.mdate(self.url) 
    1907  
    1908     def close(self): 
    1909         if not self.closed: 
    1910             if "w" in self.mode: 
    1911                 c = self._cursor() 
    1912                 c.execute(self.stream.getvalue()) 
    1913             self.stream = None 
    1914             self.closed = True 
    19151265 
    19161266 
  • src/ll/scripts/ucp.py

    r3691 r3732  
    2222    from ll import astyle 
    2323 
     24try: 
     25    from ll import orasql # activate the oracle scheme 
     26except ImportError: 
     27    pass 
     28 
    2429 
    2530def main(args=None): 
    2631    def copyone(urlread, urlwrite): 
    27         with contextlib.closing(urlread.open("rb")) as fileread: 
    28             with contextlib.closing(urlwrite.open("wb")) as filewrite: 
    29                 size = 0 
    30                 while True: 
    31                     data = fileread.read(81292) 
    32                     if data: 
    33                         filewrite.write(data) 
    34                         size += len(data) 
    35                     else: 
    36                         break 
    37         urlwrite.chown(user, group) 
    38         if options.verbose: 
    39             msg = astyle.style_default("ucp: ", astyle.style_url(str(urlread)), " -> ", astyle.style_url(str(urlwrite)), " (", str(size), " bytes)") 
    40             stderr.writeln(msg) 
     32        if urlread.isfile(): 
     33            if options.verbose: 
     34                msg = astyle.style_default("ucp: ", astyle.style_url(str(urlread)), " -> ") 
     35                stderr.write(msg) 
     36            try: 
     37                with contextlib.closing(urlread.open("rb")) as fileread: 
     38                    with contextlib.closing(urlwrite.open("wb")) as filewrite: 
     39                        size = 0 
     40                        while True: 
     41                            data = fileread.read(262144) 
     42                            if data: 
     43                                filewrite.write(data) 
     44                                size += len(data) 
     45                            else: 
     46                                break 
     47                if user or group: 
     48                    urlwrite.chown(user, group) 
     49            except Exception: 
     50                if options.ignoreerrors: 
     51                    if options.verbose: 
     52                        msg = astyle.style_error(" (failed)") 
     53                        stderr.writeln(msg) 
     54                else: 
     55                    raise 
     56            else: 
     57                if options.verbose: 
     58                    msg = astyle.style_default(astyle.style_url(str(urlwrite)), " (", str(size), " bytes)") 
     59                    stderr.writeln(msg) 
     60                 
     61        else: 
     62            if options.recursive: 
     63                for u in urlread.listdir(): 
     64                    copyone(urlread/u, urlwrite/u) 
     65            else: 
     66                if options.verbose: 
     67                    msg = astyle.style_default("ucp: ", astyle.style_url(str(urlread)), " (directory skipped)") 
     68                    stderr.writeln(msg) 
     69             
    4170 
    4271    colors = ("yes", "no", "auto") 
     
    4675    p.add_option("-u", "--user", dest="user", help="user id or name for target files") 
    4776    p.add_option("-g", "--group", dest="group", help="group id or name for target files") 
     77    p.add_option("-r", "--recursive", dest="recursive", help="Copy stuff recursively?", action="store_true", default=False) 
     78    p.add_option("-x", "--ignoreerrors", dest="ignoreerrors", help="Ignore errors?", action="store_true", default=False) 
    4879     
    4980    (options, args) = p.parse_args(args) 
  • src/ll/url.py

    r3691 r3732  
    3131        :class:`Resource` objects are file like objects that work with the actual 
    3232        bytes that make up the file data. This functionality lives in the 
    33         :class:`Resource` class and it's subclasses. Creating a resource is done 
     33        :class:`Resource` class and its subclasses. Creating a resource is done 
    3434        by calling the :meth:`open` method on a :class:`Connection` or a 
    3535        :class:`URL`. 
     
    737737                    elif cmdname == "stat": 
    738738                        if isinstance(filename, basestring): 
    739                             data = os.stat(filename) 
     739                            data = tuple(os.stat(filename)) 
    740740                        else: 
    741                             data = os.fstat(files[filename].fileno()) 
     741                            data = tuple(os.fstat(files[filename].fileno())) 
    742742                    elif cmdname == "lstat": 
    743743                        data = os.lstat(filename) 
  • src/ll/xist/publishers.py

    r3691 r3732  
    256256        return prefix 
    257257 
    258     def publish(self, node, base=None): 
    259         """ 
    260         Publish the node :var:`node`. This method is a generator that will yield 
     258    def iterbytes(self, node, base=None): 
     259        """ 
     260        Output the node :var:`node`. This method is a generator that will yield 
    261261        the resulting XML byte sequence in fragments. 
    262262        """ 
     
    309309 
    310310        self.encoder = None 
     311 
     312    def bytes(self, node, base=None): 
     313        """ 
     314        A generator that will produce a serialized byte string in XML format for 
     315        the XIST node :var:`node`. 
     316        """ 
     317        return "".join(self.iterbytes(node, base)) 
     318 
     319    def iterstring(self, node, base=None): 
     320        """ 
     321        A generator that will produce a serialized string of :var:`node`. 
     322        """ 
     323        decoder = codecs.getincrementaldecoder("xml")(encoding=self.encoding) 
     324        for part in self.iterbytes(node, base): 
     325            part = decoder.decode(part, False) 
     326            if part: 
     327                yield part 
     328        part = decoder.decode("", True) 
     329        if part: 
     330            yield part 
     331 
     332    def string(self, node, base=None): 
     333        """ 
     334        Return a serialized unicode string for :var:`node`. 
     335        """ 
     336        decoder = codecs.getdecoder("xml") 
     337        result = self.bytes(node, base) 
     338        return decoder(result, encoding=self.encoding)[0] 
     339 
     340    def write(self, stream, node, base=None): 
     341        """ 
     342        Write :var:`node` to the file-like object :var:`stream` (which must provide 
     343        a :meth:`write` method). 
     344        """ 
     345        for part in self.iterbytes(node, base): 
     346            stream.write(part) 
  • src/ll/xist/xsc.py

    r3728 r3732  
    792792            publisher = publishers.Publisher(**publishargs) 
    793793 
    794         return publisher.publish(self, base) # return a generator-iterator 
     794        return publisher.iterbytes(self, base) # return a generator-iterator 
    795795 
    796796    def bytes(self, base=None, publisher=None, **publishargs): 
     
    801801        constructor. 
    802802        """ 
    803         return "".join(self.iterbytes(base, publisher, **publishargs)) 
     803        if publisher is None: 
     804            publisher = publishers.Publisher(**publishargs) 
     805 
     806        return publisher.bytes(self, base) 
    804807 
    805808    def iterstring(self, base=None, publisher=None, **publishargs): 
     
    812815        if publisher is None: 
    813816            publisher = publishers.Publisher(**publishargs) 
    814         decoder = codecs.getincrementaldecoder("xml")(encoding=publisher.encoding) 
    815         for part in publisher.publish(self, base): 
    816             part = decoder.decode(part, False) 
    817             if part: 
    818                 yield part 
    819         part = decoder.decode("", True) 
    820         if part: 
    821             yield part 
     817 
     818        return publisher.iterstring(self, base) # return a generator-iterator 
    822819 
    823820    def string(self, base=None, publisher=None, **publishargs): 
     
    830827        if publisher is None: 
    831828            publisher = publishers.Publisher(**publishargs) 
    832         decoder = codecs.getdecoder("xml") 
    833         result = "".join(publisher.publish(self, base)) 
    834         return decoder(result, encoding=publisher.encoding)[0] 
    835  
    836     def write(self, stream, *args, **publishargs): 
     829        return publisher.string(self, base) 
     830 
     831    def write(self, stream, base=None, publisher=None, **publishargs): 
    837832        """ 
    838833        Write :var:`self` to the file-like object :var:`stream` (which must provide 
     
    842837        constructor. 
    843838        """ 
    844         for part in self.bytes(*args, **publishargs): 
    845             stream.write(part) 
     839        if publisher is None: 
     840            publisher = publishers.Publisher(**publishargs) 
     841        return publisher.write(stream, self, base) 
    846842 
    847843    def _walk(self, walkfilter, path):