Cog
Created 10 February 2004, last updated 19 November 2021
An older version of this document is also available in Russian.
Cog is a file generation tool. It lets you use pieces of Python code as generators in your source files to generate whatever text you need.
This page describes version 3.3.0, released November 19, 2021.
The sections below are:
- What does it do?
- Design
- Installation
- Writing the source files
- The cog module
- Running cog
- History
- Feedback
- See Also
What does it do?
Cog transforms files in a very simple way: it finds chunks of Python code embedded in them, executes the Python code, and inserts its output back into the original file. The file can contain whatever text you like around the Python code. It will usually be source code.
For example, if you run this file through cog:
// This is my C++ file.
...
/*[[[cog
import cog
fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing']
for fn in fnames:
cog.outl("void %s();" % fn)
]]]*/
//[[[end]]]
...
it will come out like this:
// This is my C++ file.
...
/*[[[cog
import cog
fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing']
for fn in fnames:
cog.outl("void %s();" % fn)
]]]*/
void DoSomething();
void DoAnotherThing();
void DoLastThing();
//[[[end]]]
...
Lines with triple square brackets are marker lines. The lines between [[[cog and ]]] are the generator Python code. The lines between ]]] and [[[end]]] are the output from the generator.
Output is written with cog.outl, or if you use the -P option, normal print() calls.
When cog runs, it discards the last generated Python output, executes the generator Python code, and writes its generated output into the file. All text lines outside of the special markers are passed through unchanged.
The cog marker lines can contain any text in addition to the triple square bracket tokens. This makes it possible to hide the generator Python code from the source file. In the sample above, the entire chunk of Python code is a C++ comment, so the Python code can be left in place while the file is treated as C++ code.
Design
Cog is designed to be easy to run. It writes its results back into the original file while retaining the code it executed. This means cog can be run any number of times on the same file. Rather than have a source generator file, and a separate output file, typically cog is run with one file serving as both generator and output.
Because the marker lines accommodate any language syntax, the markers can hide the cog Python code from the source file. This means cog files can be checked into source control without worrying about keeping the source files separate from the output files, without modifying build procedures, and so on.
I experimented with using a templating engine for generating code, and found myself constantly struggling with white space in the generated output, and mentally converting from the Python code I could imagine, into its templating equivalent. The advantages of a templating system (that most of the code could be entered literally) were lost as the code generation tasks became more complex, and the generation process needed more logic.
Cog lets you use the full power of Python for text generation, without a templating system dumbing down your tools for you.
Installation
Cog requires Python 2.7, 3.5, 3.6, 3.7, 3.8, or Jython 2.5.
Cog is installed in the usual way, except the name is “cogapp”, not “cog”:
$ pip install cogapp
You should now have a “cog” command, or cog.py in your Python scripts directory.
License
Cog is distributed under the MIT license. Use it to spread goodness through the world.
Writing the source files
Source files to be run through cog are mostly just plain text that will be passed through untouched. The Python code in your source file is standard Python code. Any way you want to use Python to generate text to go into your file is fine. Each chunk of Python code (between the [[[cog and ]]] lines) is called a generator and is executed in sequence.
The output area for each generator (between the ]]] and [[[end]]] lines) is deleted, and the output of running the Python code is inserted in its place. To accommodate all source file types, the format of the marker lines is irrelevant. If the line contains the special character sequence, the whole line is taken as a marker. Any of these lines mark the beginning of executable Python code:
//[[[cog
/* cog starts now: [[[cog */
-- [[[cog (this is cog Python code)
#if 0 // [[[cog
Cog can also be used in languages without multi-line comments. If the marker lines all have the same text before the triple brackets, and all the lines in the generator code also have this text as a prefix, then the prefixes are removed from all the generator lines before execution. For example, in a SQL file, this:
--[[[cog
-- import cog
-- for table in ['customers', 'orders', 'suppliers']:
-- cog.outl("drop table %s;" % table)
--]]]
--[[[end]]]
will produce this:
--[[[cog
-- import cog
-- for table in ['customers', 'orders', 'suppliers']:
-- cog.outl("drop table %s;" % table)
--]]]
drop table customers;
drop table orders;
drop table suppliers;
--[[[end]]]
Finally, a compact form can be used for single-line generators. The begin-code marker and the end-code marker can appear on the same line, and all the text between them will be taken as a single Python line:
// blah blah
//[[[cog import MyModule as m; m.generateCode() ]]]
//[[[end]]]
You can also use this form to simply import a module. The top-level statements in the module can generate the code.
If you have special requirements for the syntax of your file, you can use the --markers option to define new markers.
If there are multiple generators in the same file, they are executed with the same globals dictionary, so it is as if they were all one Python module.
Cog tries to do the right thing with white space. Your Python code can be block-indented to match the surrounding text in the source file, and cog will re-indent the output to fit as well. All of the output for a generator is collected as a block of text, a common whitespace prefix is removed, and then the block is indented to match the indentation of the cog generator. This means the left-most non-whitespace character in your output will have the same indentation as the begin-code marker line. Other lines in your output keep their relative indentation.
The cog module
A module called cog provides the functions you call to produce output into your file. The functions are:
- cog.out(sOut=’’ [, dedent=False][, trimblanklines=False])
- Writes text to the output.
- sOut is the string to write to the output.
- If dedent is True, then common initial white space is removed from the lines in sOut before adding them to the output. If trimblanklines is True, then an initial and trailing blank line are removed from sOut before adding them to the output. Together, these option arguments make it easier to use multi-line strings, and they only are useful for multi-line strings:
- cog.outl
- Same as cog.out, but adds a trailing newline.
- cog.msg(msg)
- Prints msg to stdout with a “Message: ” prefix.
- cog.error(msg)
- Raises an exception with msg as the text. No traceback is included, so that non-Python programmers using your code generators won’t be scared.
- cog.inFile
- An attribute, the path of the input file.
- cog.outFile
- An attribute, the path of the output file.
- cog.firstLineNum
- An attribute, the line number of the first line of Python code in the generator. This can be used to distinguish between two generators in the same input file, if needed.
- cog.previous
- An attribute, the text output of the previous run of this generator. This can be used for whatever purpose you like, including outputting again with cog.out().
cog.out("""
These are lines I
want to write into my source file.
""", dedent=True, trimblanklines=True)
Running cog
Cog is a command-line utility which takes arguments in standard form.
$ cog -h
cog - generate content with inlined Python code.
cog [OPTIONS] [INFILE | @FILELIST] ...
INFILE is the name of an input file, '-' will read from stdin.
FILELIST is the name of a text file containing file names or
other @FILELISTs.
OPTIONS:
-c Checksum the output to protect it against accidental change.
-d Delete the generator code from the output file.
-D name=val Define a global string available to your generator code.
-e Warn if a file has no cog code in it.
-I PATH Add PATH to the list of directories for data files and modules.
-n ENCODING Use ENCODING when reading and writing files.
-o OUTNAME Write the output to OUTNAME.
-p PROLOGUE Prepend the generator source with PROLOGUE. Useful to insert an
import line. Example: -p "import math"
-P Use print() instead of cog.outl() for code output.
-r Replace the input file with the output.
-s STRING Suffix all generated output lines with STRING.
-U Write the output with Unix newlines (only LF line-endings).
-w CMD Use CMD if the output file needs to be made writable.
A %s in the CMD will be filled with the filename.
-x Excise all the generated output without running the generators.
-z The end-output marker can be omitted, and is assumed at eof.
-v Print the version of cog and exit.
--check Check that the files would not change if run again.
--markers='START END END-OUTPUT'
The patterns surrounding cog inline instructions. Should
include three values separated by spaces, the start, end,
and end-output markers. Defaults to '[[[cog ]]] [[[end]]]'.
--verbosity=VERBOSITY
Control the amount of output. 2 (the default) lists all files,
1 lists only changed files, 0 lists no files.
-h Print this help.
In addition to running cog as a command on the command line, you can also invoke it as a module with the Python interpreter:
$ python -m cogapp [options] [arguments]
Note that the Python module is called “cogapp”.
Input files
Files on the command line are processed as input files. All input files are assumed to be UTF-8 encoded. Using a minus for a filename (-) will read the standard input.
Files can also be listed in a text file named on the command line with an @:
$ cog @files_to_cog.txt
These @-files can be nested, and each line can contain switches as well as a file to process. For example, you can create a file cogfiles.txt:
cogfiles.txt
# These are the files I run through cog
mycode.cpp
myothercode.cpp
myschema.sql -s " --**cogged**"
readme.txt -s ""
then invoke cog like this:
cog -s " //**cogged**" @cogfiles.txt
Now cog will process four files, using C++ syntax for markers on all the C++ files, SQL syntax for the .sql file, and no markers at all on the readme.txt file.
As another example, cogfiles2.txt could be:
cogfiles2.txt
template.h -D thefile=data1.xml -o data1.h
template.h -D thefile=data2.xml -o data2.h
with cog invoked like this:
cog -D version=3.4.1 @cogfiles2.txt
Cog will process template.h twice, creating both data1.h and data2.h. Both executions would define the variable version as “3.4.1”, but the first run would have thefile equal to “data1.xml” and the second run would have thefile equal to “data2.xml”.
Overwriting files
The -r flag tells cog to write the output back to the input file. If the input file is not writable (for example, because it has not been checked out of a source control system), a command to make the file writable can be provided with -w:
$ cog -r -w "p4 edit %s" @files_to_cog.txt
Setting globals
Global values can be set from the command line with the -D flag. For example, invoking Cog like this:
cog -D thefile=fooey.xml mycode.txt
will run Cog over mycode.txt, but first define a global variable called thefile with a value of “fooey.xml”. This variable can then be referenced in your generator code. You can provide multiple -D arguments on the command line, and all will be defined and available.
The value is always interpreted as a Python string, to simplify the problem of quoting. This means that:
cog -D NUM_TO_DO=12
will define NUM_TO_DO not as the integer 12, but as the string “12”, which are different and not equal values in Python. Use int(NUM_TO_DO) to get the numeric value.
Checksummed output
If cog is run with the -c flag, then generated output is accompanied by a checksum:
--[[[cog
-- import cog
-- for i in range(10):
-- cog.out("%d " % i)
--]]]
0 1 2 3 4 5 6 7 8 9
--[[[end]]] (checksum: bd7715304529f66c4d3493e786bb0f1f)
If the generated code is edited by a misguided developer, the next time cog is run, the checksum won’t match, and cog will stop to avoid overwriting the edited code.
Continuous integration
You can use the --check option to run cog just to check that the files would not change if run again. This is useful in continuous integration to check that your files have been updated properly.
Output line suffixes
To make it easier to identify generated lines when grepping your source files, the -s switch provides a suffix which is appended to every non-blank text line generated by Cog. For example, with this input file (mycode.txt):
mycode.txt
[[[cog
cog.outl('Three times:\n')
for i in range(3):
cog.outl('This is line %d' % i)
]]]
[[[end]]]
invoking cog like this:
cog -s " //(generated)" mycode.txt
will produce this output:
[[[cog
cog.outl('Three times:\n')
for i in range(3):
cog.outl('This is line %d' % i)
]]]
Three times: //(generated)
This is line 0 //(generated)
This is line 1 //(generated)
This is line 2 //(generated)
[[[end]]]
Miscellaneous
The -n option lets you tell cog what encoding to use when reading and writing files.
The --verbose option lets you control how much cog should chatter about the files it is cogging. --verbose=2 is the default: cog will name every file it considers, and whether it has changed. --verbose=1 will only name the changed files. --verbose=0 won’t mention any files at all.
The --markers option lets you control the syntax of the marker lines. The value must be a string with two spaces in it. The three markers are the three pieces separated by the spaces. The default value for markers is “[[[cog ]]] [[[end]]]”.
The -x flag tells cog to delete the old generated output without running the generators. This lets you remove all the generated output from a source file.
The -d flag tells cog to delete the generators from the output file. This lets you generate content in a public file but not have to show the generator to your customers.
The -U flag causes the output file to use pure Unix newlines rather than the platform’s native line endings. You can use this on Windows to produce Unix-style output files.
The -I flag adds a directory to the path used to find Python modules.
The -p option specifies Python text to prepend to embedded generator source, which can keep common imports out of source files.
The -z flag lets you omit the [[[end]]] marker line, and it will be assumed at the end of the file.
History
Cog’s change log is on a separate change page.
Feedback
I’d love to hear about your successes or difficulties using cog. Comment here, or send me a note.
See Also
There are a handful of other implementations of the ideas in Cog:
- Argent is a Ruby implementation.
- Precog is a PHP implementation.
- PCG is a Perl implementation.
- Templarian is a similar tool, also in Python.
- Nocog is a build tool to detect files that should be run through cog.
You might like to read:
- Cog: A Code Generation Tool Written in Python, the Python Success Story I wrote about Cog.
- My blog, where I ramble on about software and other things that interest me.
Comments
Some minor issues - the 'cog.py' file in scripts has a cr-lf at the end of the first line, which makes it fail to run, and makes distutils fail to edit in the proper python bin location. Easily fixed.
Running the script with no command line parameters should cause it to print a help message.
How about an option which will cause
cog to fail with an error if the file's
actual autogenerated code doesn't match the live python output. This might make more sense than '-r' for use in a makefile, to ensure that you don't edit the wrong code and have your changes discarded.
I notice that the 'import cog' is not actually required, this is good. It would be very nice if each python snippet were run in the same global dictionary, so you could define a variable (or import a module) at one point and use it throughout.
Finally -- certain languages (VHDL,
Makefiles, Python, for instance) do
not have multi-line comments, so
you can't use it with these, unless
I am missing something. May I suggest:
if the [[[cog is preceded by some text on its line, then all lines between that
and the ]]] are checked to see if they
start with the same text, and if so, that is discarded before further processing.
But a slightly different approach would fix that:
1. External Python or cog-CodeBehind file next to the source file.
2. You add naming to your cog-codegen slots.
This allows the CodeBehind codegen code to find the output slot for its generated code.
EXAMPLE:
// file:MyCxxFile.hpp
// SLOT-CONTE
/*[[[cog-slot:EnumerateMethods]]] */
void DoSomething();
void DoAnotherThing();
void DoLastThing();
//[[[end]]]
// file:MyCxxFile.hpp.cogCodeBehind or MyCxxFile.hpp.cog or ...
// NOTE: Comments etc. are optional now.
/*[[[cog-codeBehind:EnumerateMethods
import cog
fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing']
for fn in fnames:
cog.outl("void %s();" % fn)
]]]*/
// file: MyCxxFile.hpp
/*[[[cog
import MyCxxFileGen
]]]*/
/*[[[end]]]*/
# file: MyCxxFileGen.py
import cog
fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing']
for fn in fnames:
cog.outl("void %s();" % fn)
// [[[cog import mycodgen as m]]]
// [[[end]]]
... lots of regular code ...
// [[[cog m.somestuff()]]]
// [[[end]]]
... other code ...
// [[[cog m.otherstuff()]]]
// [[[end]]]
As it is, each cog slot seems to "forget" the globals() dict for previous cog slots (i.e. line 86 in cogapp.py passes an empty globals() dict to eval).
The mission is to eliminate any work PHP might do that relates to application configuration or the environment it's running in - stuff that won't change once an app is deployed so eliminate the runtime overhead.
One particular thing I want to keep is the ability to execute the PHP scripts, while hacking, before they have been run through COG, e.g.
/**
[[[cog
import cog
cog.outl("require_once '/full/path/to/someClass.php';")
]]]*/
// While hacking, use this
require_once DEV_PATH 'someClass.php';
//[[[end]]]
May even ditch the require_once completely and have COG embed the class code directly into the script.
Anyway - thanks.
That way I could provide the xml file to the template dynamically.
Thanks again!
Theo
I think this is a good idea. I'll add it into Cog soon.
Theo
One script I'm interested in (that I'm sure others would be too) is a script that will generate C++ functions that will translate enum values to and from string representations. Having a recipes site would allow me to share my code as well as allow others to give feedback about my script.
Anyone who has snippets to share, please post them. The Wiki will become better as more people share their code.
this is a really handy tool you wrote.
Keep up the great work.
*And why not directing the stdout instead of cog.outl ?
Thanks
One thing I noticed after just installing cog-2.0 from the tarball is that cog.out no longer seems to recognise the trimnewlines command. After grepping the source I see that it's apparently been changed to trimblanklines?
/*[[[cog
import cog
cog.outl(" extern void simple1();")
cog.outl(" extern void simple2();")
]]]*/
//[[[end]]]
I think the result should be indented, since the dedent parameter isn't given and the default value is False.
However, the result is "dedented". (reindentBlock is called twice)
To see what the dedent parameter does, try putting five spaces at the left of one of your lines, and try it with dedent=True and dedent=False to see the difference.
Sorry for the confusion. If you need the output block indented differently, indent your entire cog block to where you want the output to go.
This is some neat python app :-)
I would like to try it for some Java apps around here. Has anyone tried whether
it works with jython? If so I could easily use it from ant and would not
require people to install Python.
thanks
FYI, I have code that users must run, and the code has strings with passwords in them. I don't want users to be able to find passwords by looking at the code they run (strings show up in binary code). I'll use cog to generate encrypted strings, and when the program runs the strings will be decrypted. Users won't be able to see clear text passwords no matter what they do, except if they figure out the decryption code. This is not NSA type security, it is for ordinary users.
Of course I could manually encrypt the password strings; then I'd not need cog. But that is a lot more work as there are several programs that will use this technique, and passwords change from time to time. The python code will be very short.
g.
Thanks
thank you very much
haroldo
It saved me a lot of work.
Thx
Here are a bunch of examples of Enhanced CWEB metamacros:
I have code that has Windows line endings and got syntax errors on Linux because of them. Other developers use only Windows so changing the line endings of the file is a bit too tedious. To fix this, I had to modify the evaluate method to convert \r\n line endings to \n before running the code:
intext = "import cog\n" + intext + "\n"
intext = intext.replace("\r\n", "\n"); # Replace Windows line endings
I would like the ability to add comments in my C code (like "do not edit" or "generated from somefile.txt"), which is a bit awkward since the closing comment mark terminates the cog code.
I added this to my local version, which would be nice in a future release:
Splitting the comment isn't very "attractive", which is why I went with a wrapper (not dissimilar to how you don't _really_ need outl() - you could just use out() and add a "\\n" each time.)
Thanks again for providing cog!
Would you consider either having cog.py pass in list(sys.argv) to pass in a copy of sys.argv, or in cogapp.py set argv0=argv[0];argv_rest = argv[1:]; and then use argv_rest for parsing instead of doing argv.pop(0)?
import cog
cog.outl(" extern void simple1();")
I am having trouble running this in Eclipse/Pydev. Thanks for your help.
What do you think?
A very useful tool.
I would like to know whether, if I import one of my module in one file, then can I use the functions present in that module or any python variable defined in that cog file in other file ?
I'm using cog for automating some code generation from a text file, and I love it. It works great for removing some of the repetition from my day. Unfortunately, I've come across a bug. I read my input text file, and store my code lines in a dictionary of lists.
When I come to a specific section I loop over each line in each list, in the appropriate dictionary entry, and print them with cog.outl(). All the lines start with \t to indent them appropriately, but cog strips this out, unless I also print a line with no indent.
Currently with the latest COG available for download, I am unable to indent the code with '\t'(tab) in the beginning.
I am using cog.out and cog.outl for creating the code statements.
Currently I have changed the "reindentBlock" function in "whiteutils.py".
Changed statement to "l = l.replace(oldIndent, '\t', 1)".
Can you please check if it is a bug or am I missing something ?
inline template is very interesting to maintain codes.
It would be helpful if you added an example for how to use -D parameters. It took me a while to realise that they are visible to the code in the template, but not to the imported code, i.e. I needed to pass in the globals as parameters to my generator code.
Please consider changing line 637 in cogapp.py to (and importing glob) to allow for wildcards on Windows:
It would be usefull to automatically create directory when option -o is used.
# -*- coding: cp1251 -*-
...
...
k = ord('а') #russian unicode symbol, k = 1072
But cog gaves me ASCII code
[[[cog
#-*- coding: cp1251 -*-
import cog
def test() :
k = ord('а')
cog.out('CString strChar = _T("')
cog.out("".join("%d" % ord(k)))
cog.out('")')
]]]*/
//[[[end]]]
and it gaves me k = 224 # the same russian symbol but in ASCII
I use the same interpretator in both cases (IronPython 2.7). Can you give me an advice?
Small request: possible to add option to set verbosity, with following possibilities:
- same as now, show changed files, and unchanged files
- show only changes files
- no output at all, completely silent
The advantage is that currently, I've added it to my cmake file, with a wildcard, like 'cog.py *.h', and I'd prefer to only be notified when something change.d
- created a python module 'cog_headers.py': http://pastebin.com/8metuaMS
- then simply add a small cog declaration to each of my header files, like http://pastebin.com/wJ12uhv7
You'd better open all files with encoding="utf-8-sig" to avoid such untrackable bugs.
Oh, and I nearly forgot. Cog is awesome!
Typically, one may want to generate a skeleton that they can then fill-in with manually written code. If the generation is re-run, the manually written code should be preserved. Do you you think you could add such a feature?
Thanks for the amazing piece of code you wrote! The "dedent" feature alone is worth the price of the ticket ;-)
That is, as you would `import cog` or `import MyModule`, be able to `import MyFile.h` (obviously not using the import keyword though) so that variables in the cog section of the imported file are available to the cog in the current file?
Including a common .py file doesn't work very well for my particular use-case, which is to do a mash-up of part-generated (à la protobuf) and part-hand-written message structs.
Cog is used for generating the serialisation code, whilst allowing hand-written business logic to live alongside.
What I'm trying to do is add a validation part, where only serialisable types and Cog-generated serialisable message structs can be using in new serialisable messages (ie: you can import another message struct if you want it have it as a member)
At the moment I'm leaning towards wrapping a call to `callableMain` or `processOneFile`? I am obviously somewhat reticent to be using Cog internals when they are not part of the stable interface.
Perhaps just the price I will have to pay...
If I get a decent version working which isn't too hacky, I could submit it for review to see if you think it worthwhile to include as a feature?
I did: python setup.py install
I can find cog.py in my scripts dir:
C:\Users\b.krayenhoff\AppData\Local\Continuum\Anaconda\Scripts
Any ideas for how to get it to work?
to generate C type definition based on a ctypes class?
example:
import cog
import ctypes
class Numbers(ctypes.Structure):
_fields_ = [
('a', c_ubyte),
('a', c_ubyte)
]
cog.out_type(Numbers)
output:
struct Numbers {
unsigned char a;
unsigned char b;
};
// file: MyCxxFile.hpp
/*[[[cog
import MyCxxFileGen
]]]*/
/*[[[end]]]*/
cog -D var=12 MyCxxFile.hpp
The values you define with -D are available as globals in your Python code. Just use the name "var".
Any issues about speed you know?
It look like it spent a 0.5 sec per file with "hello world" example.
Thanks.
I use COG to generate two files, a .c and a .h. I have a common python module that initializes some data for the code generation.
Is it possible somehow that this python module shall be called once? Now I have to import it in both of my templates.
Thanks
Thanks
I have multiple cog-blocks in a file, and only the first one gets executed.
Do i need an extra parameter to tell, that cog that there are multiple blocks per file?
I used a module which defined some lists, and also imported everything from cog, and then i used outl() from my module. importing cog seperatly solved my problem
```
#!cog
[[[cog
cog.out("""
These are lines I
want to write into my source file.
""", dedent=True, trimblanklines=True)
]]]
These are lines I
want to write into my source file.
[[[end]]]
```
and **dedent=False**
```
#!cog
[[[cog
cog.out("""
These are lines I
want to write into my source file.
""", dedent=False, trimblanklines=True)
]]]
These are lines I
want to write into my source file.
[[[end]]]
```
This example is in documentation and don't work.
I installed Cog and tried one example, which failed miserably. I figured out that Cog depends on "handyxml" and the latter depends on PyXML.
Since PyXML is not available anymore, how to use handyxml and make Cog running properly using currently available tools?
Which modules to install and which modifications to make?
P.S. Sorry for posting this question both on handyxml page and here, but I'm not sure if both of them are monitored nowadays, if any.
/* [[[cog
import cog, handyxml
for p in handyxml.xpath('Properties.xml', '//property'):
cog.outl("Property%s," % p.name)
]]] */
So instead of importing handyxml I need to import some other module and use that module's methods for reading an XML file? Or is there some built-in methods not requiring other modules?
Question:
How can i use / invoke cog if i need some kind of wrapper around it (or in other words: how does one use cog from within another python-module)?
The thing is e.g. i need to extract some data from a json-file as a pre-step which should then be cross-referenced within the python-code of the sourc-code-template-files.
Therefore i need to write my own module which reads in mentioned json-data and then should invoke cog, e.g.:
1) within some own python-module:
def pre_step()
# read in json-file / data here into some data-structure
data = ...
2) within that same module invoke cog on e.g. a file test.h (how to do that?) Examples above are using it only from command line. Of course, an exex(..) or other system-call possibility is there, but is cog only intended to be used via command-line? I would have to prepare any needed data within the template itself then, or?
Thnx alot.
Is it possible to have the place holders (ie: %s be accompanied with the variable directly after it).
Current implementation is:
cog.out("codeblock %s ... %s ... %s code block" (% var1 var2 var3))
Suggested implementation is:
cog.out("codeblock %s{var1} ... %s{var2} ... %s{var3} codeblock")
or even could be combined like:
cog.out("codeblock %s{var1} ... %s ... %s{var3} codeblock" (% var2))
I find putting the variables in place will be very handy sometimes, that would save me from counting to 10 place-holders to know which variable to update.
Thanks a lot.
cog.out(f"codeblock {var1} ... {var2} ...etc")
If you need to use an earlier Python, you can do this:
cog.out("codeblock {var1} ... {var2}".format(**vars()))
I am trying to use Cog on code than might need some regeneration, and I don't see a way to let programmer write his code into part that is generated inside a loop.
For (oversimplified) c example I want to create 3 classes, and let programmer expand them after generation. Next I want to generate 4th class, and preserve what programmer has written into 3 already existing.
...
*Classes = ['A', 'B', 'C']
*for class in Classes
* cog.outl(f"class {class} ")
* cog.outl(f"{")
* cog.outl(f"public:")
* cog.outl(f"{class}(); ")
* cog.outl(f"") # here programmer wants to put his code.
* cog.outl(f"}")
...
First, let me thank you for this awesome piece of software.
I think I understand @Adam request as I may facing some similar issue. Let me explain:
I like one idea for C development that is presented in a book called "Object-Oriented Programming with ANSI-C". It basically describes a way to use OO paradigm with plain C.
The methods described in the book requires a lot of boilerplate, mainly copying 2-3 files and repeating some structures and some patterns in the class files the developer wants to create.
The book presents some kind of preprocessor to create the code but I don't like the idea as the files the developer has to create doesn't resemble C, it's like using a new DSL.
What I'm doing is creating a CLI program that allows to create a new project, create new classes, adding methods... This information is stored in a json file and then I use cog to generate the final files.
The issue comes when you want to add a new method or update the boilerplate and want all the created files to be updated. If I run cog again, the implementation added by a developer will be removed and the class files will be left again with the skeleton methods.
Sorry for the long 2 posts
We import and call function from ouside python module, but it's so easy with the cog.
thanks for cog, looks pretty cool!
I have same question as @Efendi above, not sure doing this is possible?
Just wanted to say thanks for this tool.
I'm using it autogenerate intialization tables for embedded C micro controller code. I like the way you have kept the tool language agnostic, and tied in the ever expaniding power of python. I think this tool will live on for a long time!
Best Wishes,
Brian Moran
Thanks for the great tool. One piece of functionality that would be really handy is to be able to generate code inside a template line, rather than always requiring separate lines. For example, it would be great if this could work:
```
/*[[[cog
import cog
...
# some code to load dictionary 'data'
...
]]]
[[[end]]]*/
namespace /*[[[cog cog.out(data['namespace')]]] [[[end]]]*/{
//rest of code
}
```
Should generate with -d (for example):
```
namespace myspace {
//rest of code
}
```
Obviously I appreciate the above example is trivial, but there are plenty of cases where it would be nice to generate just part of a line rather than whole lines.
Thanks,
Pavel
just used it to turn a multi file bash installer script into a single file executable, very neat!
credit for info pythonbytes
Cog is great! I’ve been using it for years. But I recently tried to install my code generator application on Linux but I’m apparently having difficulties with the cog installation.
The main thing is that I don’t see a /Scripts directory. Cog seems to have been installed in /usr/local/lib/python3.8. For example, if I run pip again, I get this:
pip3 install cogapp Requirement already satisfied: cogapp in /usr/local/lib/python3.8/dist-packages (3.4.1)
Where should I find the cog command or cog.py?
I should also add that I have tried to use cogapp.py, located here: /usr/local/lib/python3.8/dist-packages/cogapp/cogapp.py
However, when I try to reference cogapp.py (having changed it from cog.py, as I do when using cog on Windows) I get this on Linux:
ImportError: attempted relative import with no known parent package Traceback (most recent call last): File “/usr/local/lib/python3.8/dist-packages/cogapp/cogapp.py”, line 16, in from .whiteutils import commonPrefix, reindentBlock, whitePrefix
@Pierce, you should be able to just use “cog” as a command name if you have installed it into your usual Python installation.
Add a comment: